// threadtest.cc 
//	Simple test case for the threads assignment.
//
//	Create two threads, and have them context switch
//	back and forth between themselves by calling Thread::Yield, 
//	to illustratethe inner workings of the thread system.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "string.h"
#include "copyright.h"
#include "system.h"
#ifdef CHANGED
#include "synch.h"
#endif
//----------------------------------------------------------------------
// SimpleThread
// 	Loop 5 times, yielding the CPU to another ready thread 
//	each iteration.
//
//	"which" is simply a number identifying the thread, for debugging
//	purposes.
//----------------------------------------------------------------------

void
SimpleThread(int which)
{
  int num;
    
  for (num = 0; num < 5; num++) {
    printf("*** thread %d looped %d times\n", which, num);
    currentThread->Yield();
  }
}

//----------------------------------------------------------------------
// ThreadTest
// 	Set up a ping-pong between two threads, by forking a thread 
//	to call SimpleThread, and then calling SimpleThread ourselves.
//----------------------------------------------------------------------

void
ThreadTest()
{
  DEBUG('t', "Entering SimpleTest");

  Thread *t = new Thread("forked thread");

  t->Fork(SimpleThread, 1);
  SimpleThread(0);
}

#ifdef CHANGED
// --------------------------------------------------
// Test Suite
// --------------------------------------------------


// --------------------------------------------------
// Test 1 - see TestSuite() for details
// --------------------------------------------------
Semaphore t1_s1("t1_s1",0);       // To make sure t1_t1 acquires the
                                  // lock before t1_t2
Semaphore t1_s2("t1_s2",0);       // To make sure t1_t2 Is waiting on the 
                                  // lock before t1_t3 releases it
Semaphore t1_s3("t1_s3",0);       // To make sure t1_t1 does not release the
                                  // lock before t1_t3 tries to acquire it
Semaphore t1_done("t1_done",0);   // So that TestSuite knows when Test 1 is
                                  // done
Lock t1_l1("t1_l1");		  // the lock tested in Test 1

// --------------------------------------------------
// t1_t1() -- test1 thread 1
//     This is the rightful lock owner
// --------------------------------------------------
void t1_t1() {
  t1_l1.Acquire();
  t1_s1.V();  // Allow t1_t2 to try to Acquire Lock
 
  printf ("%s: Acquired Lock %s, waiting for t3\n",currentThread->getName(),
	  t1_l1.getName());
  t1_s3.P();
  printf ("%s: working in CS\n",currentThread->getName());
  for (int i = 0; i < 1000000; i++) ;
  printf ("%s: Releasing Lock %s\n",currentThread->getName(),
	  t1_l1.getName());
  t1_l1.Release();
  t1_done.V();
}

// --------------------------------------------------
// t1_t2() -- test1 thread 2
//     This thread will wait on the held lock.
// --------------------------------------------------
void t1_t2() {

  t1_s1.P();	// Wait until t1 has the lock
  t1_s2.V();  // Let t3 try to acquire the lock

  printf("%s: trying to acquire lock %s\n",currentThread->getName(),
	 t1_l1.getName());
  t1_l1.Acquire();

  printf ("%s: Acquired Lock %s, working in CS\n",currentThread->getName(),
	  t1_l1.getName());
  for (int i = 0; i < 10; i++)
    ;
  printf ("%s: Releasing Lock %s\n",currentThread->getName(),
	  t1_l1.getName());
  t1_l1.Release();
  t1_done.V();
}

// --------------------------------------------------
// t1_t3() -- test1 thread 3
//     This thread will try to release the lock illegally
// --------------------------------------------------
void t1_t3() {

  t1_s2.P();	// Wait until t2 is ready to try to acquire the lock

  t1_s3.V();	// Let t1 do it's stuff
  for ( int i = 0; i < 3; i++ ) {
    printf("%s: Trying to release Lock %s\n",currentThread->getName(),
	   t1_l1.getName());
    t1_l1.Release();
  }
}

// --------------------------------------------------
// Test 2 - see TestSuite() for details
// --------------------------------------------------
Lock t2_l1("t2_l1");		// For mutual exclusion
Condition t2_c1("t2_c1");	// The condition variable to test
Semaphore t2_s1("t2_s1",0);	// To ensure the Signal comes before the wait
Semaphore t2_done("t2_done",0);     // So that TestSuite knows when Test 2 is
// done

// --------------------------------------------------
// t2_t1() -- test 2 thread 1
//     This thread will signal a variable with nothing waiting
// --------------------------------------------------
void t2_t1() {
  t2_l1.Acquire();
  printf("%s: Lock %s acquired, signalling %s\n",currentThread->getName(),
	 t2_l1.getName(), t2_c1.getName());
  t2_c1.Signal(&t2_l1);
  printf("%s: Releasing Lock %s\n",currentThread->getName(),
	 t2_l1.getName());
  t2_l1.Release();
  t2_s1.V();	// release t2_t2
  t2_done.V();
}

// --------------------------------------------------
// t2_t2() -- test 2 thread 2
//     This thread will wait on a pre-signalled variable
// --------------------------------------------------
void t2_t2() {
  t2_s1.P();	// Wait for t2_t1 to be done with the lock
  t2_l1.Acquire();
  printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
	 t2_l1.getName(), t2_c1.getName());
  t2_c1.Wait(&t2_l1);
  printf("%s: Releasing Lock %s\n",currentThread->getName(),
	 t2_l1.getName());
  t2_l1.Release();
}
// --------------------------------------------------
// Test 3 - see TestSuite() for details
// --------------------------------------------------
Lock t3_l1("t3_l1");		// For mutual exclusion
Condition t3_c1("t3_c1");	// The condition variable to test
Semaphore t3_s1("t3_s1",0);	// To ensure the Signal comes before the wait
Semaphore t3_done("t3_done",0); // So that TestSuite knows when Test 3 is
                                // done

// --------------------------------------------------
// t3_waiter()
//     These threads will wait on the t3_c1 condition variable.  Only
//     one t3_waiter will be released
// --------------------------------------------------
void t3_waiter() {
  t3_l1.Acquire();
  t3_s1.V();		// Let the signaller know we're ready to wait
  printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
	 t3_l1.getName(), t3_c1.getName());
  t3_c1.Wait(&t3_l1);
  printf("%s: freed from %s\n",currentThread->getName(), t3_c1.getName());
  t3_l1.Release();
  t3_done.V();
}


// --------------------------------------------------
// t3_signaller()
//     This threads will signal the t3_c1 condition variable.  Only
//     one t3_signaller will be released
// --------------------------------------------------
void t3_signaller() {

  // Don't signal until someone's waiting
    
  for ( int i = 0; i < 5 ; i++ ) 
    t3_s1.P();
  t3_l1.Acquire();
  printf("%s: Lock %s acquired, signalling %s\n",currentThread->getName(),
	 t3_l1.getName(), t3_c1.getName());
  t3_c1.Signal(&t3_l1);
  printf("%s: Releasing %s\n",currentThread->getName(), t3_l1.getName());
  t3_l1.Release();
  t3_done.V();
}
 
// --------------------------------------------------
// Test 4 - see TestSuite() for details
// --------------------------------------------------
Lock t4_l1("t4_l1");		// For mutual exclusion
Condition t4_c1("t4_c1");	// The condition variable to test
Semaphore t4_s1("t4_s1",0);	// To ensure the Signal comes before the wait
Semaphore t4_done("t4_done",0); // So that TestSuite knows when Test 4 is
                                // done

// --------------------------------------------------
// t4_waiter()
//     These threads will wait on the t4_c1 condition variable.  All
//     t4_waiters will be released
// --------------------------------------------------
void t4_waiter() {
  t4_l1.Acquire();
  t4_s1.V();		// Let the signaller know we're ready to wait
  printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
	 t4_l1.getName(), t4_c1.getName());
  t4_c1.Wait(&t4_l1);
  printf("%s: freed from %s\n",currentThread->getName(), t4_c1.getName());
  t4_l1.Release();
  t4_done.V();
}


// --------------------------------------------------
// t2_signaller()
//     This thread will broadcast to the t4_c1 condition variable.
//     All t4_waiters will be released
// --------------------------------------------------
void t4_signaller() {

  // Don't broadcast until someone's waiting
    
  for ( int i = 0; i < 5 ; i++ ) 
    t4_s1.P();
  t4_l1.Acquire();
  printf("%s: Lock %s acquired, broadcasting %s\n",currentThread->getName(),
	 t4_l1.getName(), t4_c1.getName());
  t4_c1.Broadcast(&t4_l1);
  printf("%s: Releasing %s\n",currentThread->getName(), t4_l1.getName());
  t4_l1.Release();
  t4_done.V();
}
// --------------------------------------------------
// Test 5 - see TestSuite() for details
// --------------------------------------------------
Lock t5_l1("t5_l1");		// For mutual exclusion
Lock t5_l2("t5_l2");		// Second lock for the bad behavior
Condition t5_c1("t5_c1");	// The condition variable to test
Semaphore t5_s1("t5_s1",0);	// To make sure t5_t2 acquires the lock after
                                // t5_t1

// --------------------------------------------------
// t5_t1() -- test 5 thread 1
//     This thread will wait on a condition under t5_l1
// --------------------------------------------------
void t5_t1() {
  t5_l1.Acquire();
  t5_s1.V();	// release t5_t2
  printf("%s: Lock %s acquired, waiting on %s\n",currentThread->getName(),
	 t5_l1.getName(), t5_c1.getName());
  t5_c1.Wait(&t5_l1);
  printf("%s: Releasing Lock %s\n",currentThread->getName(),
	 t5_l1.getName());
  t5_l1.Release();
}

// --------------------------------------------------
// t5_t1() -- test 5 thread 1
//     This thread will wait on a t5_c1 condition under t5_l2, which is
//     a Fatal error
// --------------------------------------------------
void t5_t2() {
  t5_s1.P();	// Wait for t5_t1 to get into the monitor
  t5_l1.Acquire();
  t5_l2.Acquire();
  printf("%s: Lock %s acquired, signalling %s\n",currentThread->getName(),
	 t5_l2.getName(), t5_c1.getName());
  t5_c1.Signal(&t5_l2);
  printf("%s: Releasing Lock %s\n",currentThread->getName(),
	 t5_l2.getName());
  t5_l2.Release();
  printf("%s: Releasing Lock %s\n",currentThread->getName(),
	 t5_l1.getName());
  t5_l1.Release();
}

// --------------------------------------------------
// TestSuite()
//     This is the main thread of the test suite.  It runs the
//     following tests:
//
//       1.  Show that a thread trying to release a lock it does not
//       hold does not work
//
//       2.  Show that Signals are not stored -- a Signal with no
//       thread waiting is ignored
//
//       3.  Show that Signal only wakes 1 thread
//
//	 4.  Show that Broadcast wakes all waiting threads
//
//       5.  Show that Signalling a thread waiting under one lock
//       while holding another is a Fatal error
//
//     Fatal errors terminate the thread in question.
// --------------------------------------------------
void TestSuite() {
  Thread *t;
  char *name;
  int i;
    
  // Test 1

  printf("Starting Test 1\n");

  t = new Thread("t1_t1");
  t->Fork((VoidFunctionPtr)t1_t1,0);

  t = new Thread("t1_t2");
  t->Fork((VoidFunctionPtr)t1_t2,0);

  t = new Thread("t1_t3");
  t->Fork((VoidFunctionPtr)t1_t3,0);

  // Wait for Test 1 to complete
  for (  i = 0; i < 2; i++ )
    t1_done.P();

  // Test 2

  printf("Starting Test 2.  Note that it is an error if thread t2_t2\n");
  printf("completes\n");

  t = new Thread("t2_t1");
  t->Fork((VoidFunctionPtr)t2_t1,0);

  t = new Thread("t2_t2");
  t->Fork((VoidFunctionPtr)t2_t2,0);

  // Wait for Test 2 to complete
  t2_done.P();

  // Test 3

  printf("Starting Test 3\n");

  for (  i = 0 ; i < 5 ; i++ ) {
    name = new char [20];
    sprintf(name,"t3_waiter%d",i);
    t = new Thread(name);
    t->Fork((VoidFunctionPtr)t3_waiter,0);
  }
  t = new Thread("t3_signaller");
  t->Fork((VoidFunctionPtr)t3_signaller,0);

  // Wait for Test 3 to complete
  for (  i = 0; i < 2; i++ )
    t3_done.P();

  // Test 4

  printf("Starting Test 4\n");

  for (  i = 0 ; i < 5 ; i++ ) {
    name = new char [20];
    sprintf(name,"t4_waiter%d",i);
    t = new Thread(name);
    t->Fork((VoidFunctionPtr)t4_waiter,0);
  }
  t = new Thread("t4_signaller");
  t->Fork((VoidFunctionPtr)t4_signaller,0);

  // Wait for Test 4 to complete
  for (  i = 0; i < 6; i++ )
    t4_done.P();

  // Test 5

  printf("Starting Test 5.  Note that it is an error if thread t5_t1\n");
  printf("completes\n");

  t = new Thread("t5_t1");
  t->Fork((VoidFunctionPtr)t5_t1,0);

  t = new Thread("t5_t2");
  t->Fork((VoidFunctionPtr)t5_t2,0);

}


#ifdef THREADS

/*************************************

  PASSPORT SIMULATION CODE BEGINS HERE

**************************************/

//Defining the max number of each clerk type and customer
#define MAXCUSTOMERS 30
#define MAXLINES 5 //per each clerk
#define MAXAPPCLERKS 5 
#define MAXPICCLERKS 5 
#define MAXPASSPORTCLERKS 5
#define MAXCASHIERS 5

/*used as default value for int values
  since 0 maybe already used*/
#define LARGENUMBER 500

//Initializing number of customer inside the passport office
int totalCust = 0;

//Defining possible states for customers and clerks.
enum CustomerState {created,waitingInLine,atDesk,pictureTaken,appTaken,passportGiven,payed};
enum ClerkType {none,application,picture,passport,cashier};
enum ClerkState {started,Ready,WaitingOnCustomer,Busy,OnBreak};
enum Passport {empty,approved,rejected};
enum SenatorState {NA,waiting,acknowledged,active,finished};

//STRUCTS:
/*
  primary means through which a customer 
  communicates/interacts with a clerk
*/
typedef struct
{
  //Lock and Condition variable to solve race condition and mutual exclusion.
  Lock *waitingLine_L;
  Condition *waiting_App;

  Lock *goingOnBreak;
  Condition *wakeUp;

  int money;
  ClerkState state;
  int SSN;//currently being served ssn (only valid while busy)
  bool customerAtDesk; //customer currently waiting
  bool isOccupied; //is there even a clerk at this desk
  
}AppClerk;


typedef struct
{
  //Lock and Condition variable to solve race condition and mutual exclusion.
  Lock *waitingLine_L;
  Condition *waiting_Pic;
  
  Lock *goingOnBreak;
  Condition *wakeUp;

  int money;
  ClerkState state;
  int SSN;//currently being served ssn (only valid while busy)
  bool customerAtDesk; //customer currently waiting
  bool isOccupied; //is there even a clerk at this desk
  
}PicClerk;

typedef struct
{
  //Lock and Condition variable to solve race condition and mutual exclusion.
  Lock *waitingLine_L;
  Condition *waiting_App;
  
  Lock *goingOnBreak;
  Condition *wakeUp;

  int money;
  int SSN;//used to track who is approved for passport
  ClerkState state;
  bool customerAtDesk;//customer currently waiting
  bool isOccupied;//is there even a clerk at this desk

}PassClerk;

typedef struct
{
  //Lock and Condition variable to solve race condition and mutual exclusion.
  Lock *waitingLine_L;
  Condition *waiting_App;
  
  Lock *goingOnBreak;
  Condition *wakeUp;

  int money;
  int SSN;//used to track who is approved for passport
  Passport passState;//shared data for customer to check on passport
  ClerkState state;
  bool customerAtDesk;//customer currently waiting
  bool isOccupied;//is there even a clerk at this desk

}Cashier;

typedef struct
{
  SenatorState state;
  //Lock and Condition variable to solve race condition and mutual exclusion.
  Lock *active;
  Condition *waiting;

}Senator;

/*
  global array of approved customers
  customers removed once they are done
  accessed by passport clerk and cashier clerk
  array instead of list because FIFO is not 
  needed here
*/
int passports[MAXCUSTOMERS];

//CLERK ARRAYS
AppClerk appClerkDesk[MAXAPPCLERKS];
PicClerk picClerkDesk[MAXPICCLERKS];
PassClerk passClerkDesk[MAXPASSPORTCLERKS];
Cashier cashierDesk[MAXCASHIERS];


//Senator Status
Senator senator;
//.state = NA;


/*array of things a customer needs
  filed, each one has ssn's
  and their respective locks*/
Lock appOK_L("appOK Lock");
int appOK[MAXCUSTOMERS] = {LARGENUMBER};

Lock picOK_L("picOK Lock");
int picOK[MAXCUSTOMERS] = {LARGENUMBER};

Lock passOK_L("passOK Lock");
int passOK[MAXCUSTOMERS] = {LARGENUMBER};

Lock passDone_L("passport Done Lock");
int passDone[MAXCUSTOMERS] = {LARGENUMBER};

/*
  ------------------------------------
  *
  *         LINE CODE:
  *
  -----------------------------------
*/

/*add customer lock here
  so that it is released before the 
  thread goes to sleep
*/
Lock *addCustomerLock = new Lock("addCustomer");
Condition *managerRemoveCustomer= new Condition("manager RemoveCustomer");

class Line
{
  
public:
  
  Line()
  {
    //constructor
    lineLength = 0;
    lock = new Lock("lineLock");
    lineVariable = new Condition("lineCondition");
  }
  
  ~Line()
  {
  }

  int size()
  {
    return lineLength;
  }
  void setSize(int ns){
    //used in test case to check what manager does if lineLength >=3
    lineLength=ns;
  }

  void addCustomer()
  {
    //add customer in line by first aquiring the lock for the line
    lock->Acquire();

    addCustomerLock->Release();//acquired in LineManager
    lineLength++;
    lineVariable->Wait(lock);

    lock->Release();
  }
  
  //for when a customer get to the 
  //front of the line
  void removeCustomer()
  {
    //remove customer in line by first aquiring the lock for the line.
    lock->Acquire();
    
    if(lineLength != 0)
      {
	lineLength--;
	lineVariable->Signal(lock);
      }

    lock->Release();
  }
  
  
private:
  //line class data
  int lineLength;
  Condition *lineVariable;//for waking them up
  Lock *lock; //may be redundant 
};


//LINES:
Line picClerkLine;
Line appClerkLine;
Line passClerkLine;
Line cashierLine;

//PREFERRED LINES:
Line preferred_picClerkLine;
Line preferred_appClerkLine;
Line preferred_passClerkLine;
Line preferred_cashierLine;

//WAIT LINES FOR WHEN SENATOR IS HERE:
Line wait_OutsideLine; //For customers who already are in a line
Line wait_DecideLine; //Customers who hasn't decided which line to wait in yet

//LINE LOCKS:
Lock *appLineLock = new Lock("Regular App Line Lock");
Lock *picLineLock = new Lock("Regular Pic Line Lock");
Lock *passLineLock = new Lock("Regular Passport Line Lock");
Lock *cashierLineLock = new Lock("Regular Cashier Line Lock");

Lock *preferred_appLineLock = new Lock("Preferred App Line Lock");
Lock *preferred_picLineLock = new Lock("Preferred Pic Line Lock");
Lock *preferred_passLineLock = new Lock("Preferred Passport Line Lock");
Lock *preferred_cashierLineLock = new Lock("Preferred Cashier Line Lock");

Lock *outsideLineLock = new Lock("Outside Line Lock");
Lock *decideLineLock = new Lock("Decision Line Lock");



//if Senator's here, place me in the senator wait line
void isSenatorHere(Line *custLine){

  //Check whether the senator is here
  //if(senator.state != NA && senator.state != finished){
  if(senator.state == acknowledged || senator.state == active){
    //He is, so add me to the senator wait line
    printf("%s: Senator is here, so I have to wait outside\n", currentThread->getName());
    addCustomerLock->Acquire();
    wait_OutsideLine.addCustomer();

    //Now that senator is gone, add me back to the original line
    addCustomerLock->Acquire();
    printf("%s: Senator is gone, going back to original line (", currentThread->getName());
 
    if(custLine == &appClerkLine){
      printf("Reg. Application Line)\n");
    }
    else if(custLine == &picClerkLine){
      printf("Reg. Picture Line)\n");
    }
    else if(custLine == &passClerkLine){
      printf("Reg. Passport Line)\n");
    }
    else if(custLine == &cashierLine){
      printf("Reg. Cashier Line)\n");
    }
    else if(custLine == &preferred_appClerkLine){
      printf("Pref. Application Line)\n");
    }
    else if(custLine == &preferred_picClerkLine){
      printf("Pref. Picture Line)\n");
    }
    else if(custLine == &preferred_passClerkLine){
      printf("Pref. Passport Line)\n");
    }
    else if(custLine == &preferred_cashierLine){
      printf("Pref. Cashier Line)\n");
    }
    else printf("BAD LINE ERROR)\n");
    managerRemoveCustomer->Signal(addCustomerLock);
    custLine->addCustomer();
  }
}

/*find the shortest line appropriate line
  the integer is the index of the clerk whose 
  line it is
  I agree that the return type could be better*/
int PlaceMeInLine(ClerkType *clerktype, int custMoney, int ssn)
{
  //first acquire the lock to avoid race condition
  addCustomerLock->Acquire();
    
  //Check if senator is here before finding a line
  //if(senator.state != NA && senator.state != finished){
  if(senator.state == acknowledged || senator.state == active){
    printf("%s: Senator is here, so I will wait outside before choosing line\n", currentThread->getName());
    wait_DecideLine.addCustomer();
      
    printf("%s: Senator is gone, now I will choose my line (No Line Chosen Yet)\n", currentThread->getName());
  }

  //only for clerk choice
  if(*clerktype == none)
    {
      //line size being compared accessed so lock here
      //NOTE: lineLock is released in the addCustomer function
      if(picClerkLine.size() < appClerkLine.size())
	{
	  //go to picClerkLine since the line length is shorter
	  *clerktype = picture;
	  if((custMoney>500) && (picClerkLine.size() >0)){
	    //if customer has more than $500 and the regular picClerkLine already has customers, go to preferred line.
	    custMoney -= 500;
	    printf("%s%d: chose the preferred picture clerk line\n",currentThread->getName(),ssn);
	    preferred_picClerkLine.addCustomer();
	    isSenatorHere(&preferred_picClerkLine);
	  }
	  else{
	    //go to regular line
	    printf("%s%d: chose the regular picture clerk line\n",currentThread->getName(),ssn);
	    picClerkLine.addCustomer();	 
	    isSenatorHere(&picClerkLine);
	  }
	}
	
      else 
	{
	  //go to appClerkLine since the line length is shorter or equal to picClerkLine
	  *clerktype = application;

	  if((custMoney>500) && (appClerkLine.size() > 0)){
	    //if customer has more than $500 and the regular appClerkLine already has customers, go to preferred line.
	    custMoney -= 500;
	    printf("%s%d: chose the preferred application clerk line\n",currentThread->getName(),ssn);
	    preferred_appClerkLine.addCustomer();
	    isSenatorHere(&preferred_appClerkLine);
	  }
	  else{
	    //go to regular line
	    printf("%s%d: chose the regular application clerk line\n",currentThread->getName(),ssn);
	    appClerkLine.addCustomer();
	    isSenatorHere(&appClerkLine);
	  }
	    
	}
    }
    
    
    
  //if chose picture the first time
  else if(*clerktype == application)
    {
	
      if((custMoney>500) && (appClerkLine.size() > 0)){
	//if customer has more than $500 and the regular appClerkLine already has customers, go to preferred line.
	custMoney -= 500;
	printf("%s%d: chose the preferred application clerk line\n",currentThread->getName(),ssn);
	preferred_appClerkLine.addCustomer();
	isSenatorHere(&preferred_appClerkLine);
      }
      else{
	//go to regular line
	printf("%s%d: chose the regular application clerk line\n",currentThread->getName(),ssn);
	appClerkLine.addCustomer();
	isSenatorHere(&appClerkLine);
      }
	
	
    }
    
  //if chose application the first time
  else if(*clerktype == picture)
    {
      if((custMoney>500) && (picClerkLine.size() > 0)){
	//if customer has more than $500 and the regular picClerkLine already has customers, go to preferred line.
	custMoney -= 500;
	printf("%s%d: chose the preferred picture clerk line\n",currentThread->getName(),ssn);
	preferred_picClerkLine.addCustomer();
	isSenatorHere(&preferred_picClerkLine);
      }
      else{
	//go to regular line
	printf("%s%d: chose the regular picture clerk line\n",currentThread->getName(),ssn);
	picClerkLine.addCustomer();
	isSenatorHere(&picClerkLine);
      }
    }

  else if(*clerktype == passport)
    {
      if((custMoney>500) && (passClerkLine.size() > 0)){
	//if customer has more than $500 and the regular passClerkLine already has customers, go to preferred line.
	custMoney -= 500;
	printf("%s%d: chose the preferred passport clerk line\n",currentThread->getName(),ssn);
	preferred_passClerkLine.addCustomer();
	isSenatorHere(&preferred_passClerkLine);
      }
      else{
	//go to regular line
	printf("%s%d: chose the regular passport clerk line\n",currentThread->getName(),ssn);
	passClerkLine.addCustomer();
	isSenatorHere(&passClerkLine);
      }
    }
  else if(*clerktype == cashier)
    {
      if((custMoney>500) && (cashierLine.size() > 0)){
	//if customer has more than $600 and the regular cashierLine already has customers, go to preferred line.
	custMoney -= 600;
	printf("%s%d: chose the preferred cashier line\n",currentThread->getName(),ssn);
	preferred_cashierLine.addCustomer();
	isSenatorHere(&preferred_cashierLine);
      }
      else{
	// go to regular line and pay $100 for the passport
	custMoney -= 100;
	printf("%s%d: chose the regular cashier line\n",currentThread->getName(),ssn);
	cashierLine.addCustomer();
	isSenatorHere(&cashierLine);
      }
    }
  return custMoney;
}


/*  
    ----------------------------------
    *
    *       APPLICATION CLERK:
    *
    ---------------------------------
*/

//keeping track of AppClerkIndex for multiple appliation clerks
int nextAppClerkIndex = 0;

void ApplicationClerk()
{
  printf("ApplicationClerk Thread %s is made and currently running\n",currentThread->getName());
  
  int myIndex = nextAppClerkIndex;
  nextAppClerkIndex++;
  
  appClerkDesk[myIndex];
  //initialize my values 
  appClerkDesk[myIndex].waitingLine_L = new Lock("waiting line_L");
  appClerkDesk[myIndex].waiting_App = new Condition("waiting_App");

  appClerkDesk[myIndex].goingOnBreak = new Lock("Going on Break");
  appClerkDesk[myIndex].wakeUp = new Condition("wake Up");

  appClerkDesk[myIndex].waitingLine_L->Acquire();

  appClerkDesk[myIndex].money = 0;
  appClerkDesk[myIndex].state = Ready;
  appClerkDesk[myIndex].SSN = LARGENUMBER;
  appClerkDesk[myIndex].customerAtDesk = false;
  appClerkDesk[myIndex].isOccupied = true;

  printf("%s: initialized with array index %d and waiting for customers\n",currentThread->getName(),myIndex);
  
  appClerkDesk[myIndex].waitingLine_L->Release();
  
  //main waiting on customers loop
  while(true)
    {
      //Serve senator if he is here and acknowledged
      senator.active->Acquire();
      if(senator.state == acknowledged  || senator.state == active){
	senator.active->Release();

	printf("%s: senator here, emptying out lines\n", currentThread->getName());
	while(appClerkLine.size() > 0){
	  appClerkLine.removeCustomer();
	}
	while(preferred_appClerkLine.size() > 0){
	  preferred_appClerkLine.removeCustomer();
	}

	//Signal and wait for senator
	printf("%s: emptied lines, waiting for senator\n", currentThread->getName());
	appClerkDesk[myIndex].waitingLine_L->Acquire();
	appClerkDesk[myIndex].state = WaitingOnCustomer;

	if(myIndex == 0){	  
	  senator.waiting->Signal(senator.active);
	}
	appClerkDesk[myIndex].waiting_App->Wait(appClerkDesk[myIndex].waitingLine_L);

	//Interaction with senator
	if(appClerkDesk[myIndex].customerAtDesk)
	  {
	    printf("%s: interacting with senator of ssn %d\n",currentThread->getName(),  appClerkDesk[myIndex].SSN);
	    
	    appClerkDesk[myIndex].customerAtDesk = false;

	    printf("%s: senator application filed, interaction finished\n",currentThread->getName());
	    //senator.waiting->Signal(senator.active);
	    appClerkDesk[myIndex].waiting_App->Signal(appClerkDesk[myIndex].waitingLine_L);

	    //Finished interacting with senator, wait until senator is done with passport office
	    appClerkDesk[myIndex].waiting_App->Wait(appClerkDesk[myIndex].waitingLine_L);
	  }
	appClerkDesk[myIndex].waitingLine_L->Release();

	//Signaled that the senator is gone.
	//Clerk is ready again
	appClerkDesk[myIndex].state = Ready;
	printf("%s: senator is gone, I am ready to serve customers again\n", currentThread->getName());
	//Continue onto the next loop
	//continue;
      }
      else senator.active->Release();


      //Serve the customers
      appClerkDesk[myIndex].waitingLine_L->Acquire();
      //no customers in the line
      if((appClerkLine.size() == 0) && (preferred_appClerkLine.size() == 0))
	{
	  appClerkDesk[myIndex].waitingLine_L->Release();
	  
	  //Go on break
	  printf("%s: line empty going on break\n",currentThread->getName());
      	  appClerkDesk[myIndex].goingOnBreak->Acquire();
	  appClerkDesk[myIndex].state = OnBreak;
	  appClerkDesk[myIndex].isOccupied = false;
	  appClerkDesk[myIndex].wakeUp->Wait(appClerkDesk[myIndex].goingOnBreak);

	  //Woken up, ready to serve again.
	  appClerkDesk[myIndex].state = Ready;
	  appClerkDesk[myIndex].goingOnBreak->Release();
	  printf("%s: OK, i'm off break, ready to serve customers\n", currentThread->getName());
	  
	}
      //Check if there is anyone in preferred_appClerkLine.  if there is someone serve him.
      else if(!appClerkDesk[myIndex].customerAtDesk && 
	      preferred_appClerkLine.size() > 0 &&
	      appClerkDesk[myIndex].state == Ready)
	{
	  printf("%s: waiting for preferred customers\n",currentThread->getName());
	  //preferred customer must pay 500.
	  appClerkDesk[myIndex].money += 500;
	  printf("%s: preferred customer paid.  appClerkMoney:%d\n",currentThread->getName(),appClerkDesk[myIndex].money);
	  preferred_appClerkLine.removeCustomer();
	  
	  appClerkDesk[myIndex].state = WaitingOnCustomer;
	  //wait for customer to come to desk, does not have to be signaled customer
	  appClerkDesk[myIndex].waiting_App->Wait(appClerkDesk[myIndex].waitingLine_L);

	  //if first customer from line picks this clerk
	  if(appClerkDesk[myIndex].customerAtDesk)
	    {
	      printf("%s: interacting with customer of ssn %d\n",currentThread->getName(),  appClerkDesk[myIndex].SSN);

	      appClerkDesk[myIndex].customerAtDesk = false;
	      printf("%s: customer interaction finished\n",currentThread->getName());
	      //wake current customer back up
	      appClerkDesk[myIndex].waiting_App->Signal(appClerkDesk[myIndex].waitingLine_L);



	      //FILE CODE:
	      int fileTime = (rand()%80) + 20;
	      for (int i = 0; i < fileTime; i++)
		{
		  currentThread->Yield();
		}
	       
	      //find available slot to file ssn
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  appOK_L.Acquire();
		  
		  if(appOK[i] == LARGENUMBER)
		    {
		      appOK[i] =   appClerkDesk[myIndex].SSN;
		      i = MAXCUSTOMERS; //now exit
		    }
		  appOK_L.Release();
		}

	      printf("%s: after yielding %d times, application filed for customer of ssn %d\n",currentThread->getName(),fileTime, appClerkDesk[myIndex].SSN);
	    }
	  
	  appClerkDesk[myIndex].state = Ready;
	  appClerkDesk[myIndex].waitingLine_L->Release();
	  
	}

      /*if no customer at desk but customers in line and 
	ready then signal next customer*/
      //if there was no one in preferred line and there is someone in regular line serve that customer
      else if(!appClerkDesk[myIndex].customerAtDesk && 
	      appClerkLine.size() > 0 &&
	      appClerkDesk[myIndex].state == Ready)
	{
	  printf("%s: waiting for customers\n",currentThread->getName());
	  appClerkLine.removeCustomer();
	  
	  appClerkDesk[myIndex].state = WaitingOnCustomer;
	  //wait for customer to come to desk, does not have to be signaled customer
	  appClerkDesk[myIndex].waiting_App->Wait(appClerkDesk[myIndex].waitingLine_L);

	  //if first customer from line picks this clerk
	  if(appClerkDesk[myIndex].customerAtDesk)
	    {
	      printf("%s: interacting with customer of ssn %d\n",currentThread->getName(),  appClerkDesk[myIndex].SSN);
	   
	      

	      appClerkDesk[myIndex].customerAtDesk = false;
	      printf("%s: customer of ssn %d interaction finished\n",currentThread->getName(),appClerkDesk[myIndex].SSN);
	      //wake current customer back up
	      appClerkDesk[myIndex].waiting_App->Signal(appClerkDesk[myIndex].waitingLine_L);
	       

	      //FILE CODE:
	      int fileTime = (rand()%80) + 20;
	      for (int i = 0; i < fileTime; i++)
		{
		  currentThread->Yield();
		}
	       
	      //find available slot to file ssn
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  appOK_L.Acquire();

		  if(appOK[i] == LARGENUMBER)
		    {
		      appOK[i] =   appClerkDesk[myIndex].SSN;
		      i = MAXCUSTOMERS; //now exit
		    }
		  appOK_L.Release();
		}

	      printf("%s: after yielding %d times, application filed for customer of ssn %d\n",currentThread->getName(),fileTime, appClerkDesk[myIndex].SSN);
	    }
	   
	  appClerkDesk[myIndex].state = Ready;
	  appClerkDesk[myIndex].waitingLine_L->Release();
	   
	}
      
      else 
	{
	  //Check for error.
	  appClerkDesk[myIndex].waitingLine_L->Release();
	  printf("%s: error found nothing to do!\n",currentThread->getName());
	}
    }
      
}



/*  
    ----------------------------------
    *
    *       PICTURE CLERK:
    *
    ---------------------------------
*/


int nextPicClerkIndex = 0;

void PictureClerk()
{
  printf("PictureClerk Thread %s is made and currently running\n",currentThread->getName()); 
  //  int a = rand()%100;
  //  printf("random number:  %d",a);
  int myIndex = nextPicClerkIndex;
  nextPicClerkIndex++;
  
  picClerkDesk[myIndex];
  //initialize my values 
  picClerkDesk[myIndex].waitingLine_L = new Lock("waiting line_L");
  picClerkDesk[myIndex].waiting_Pic = new Condition("waiting_Pic");

  picClerkDesk[myIndex].goingOnBreak = new Lock("Going on Break");
  picClerkDesk[myIndex].wakeUp = new Condition("Wake Up");

  picClerkDesk[myIndex].waitingLine_L->Acquire();

  picClerkDesk[myIndex].money = 0;
  picClerkDesk[myIndex].state = Ready;
  picClerkDesk[myIndex].SSN = LARGENUMBER;
  picClerkDesk[myIndex].customerAtDesk = false;
  picClerkDesk[myIndex].isOccupied = true;

  printf("%s: initialized with array index %d and waiting for customers\n",currentThread->getName(),myIndex);

  //wait until a cutstomer arrives
  //picClerkDesk[myIndex].waiting_Pic->Wait(picClerkDesk[myIndex].waitingLine_L);
  picClerkDesk[myIndex].waitingLine_L->Release();

  //main waiting on customers loop
  while(true)
    {
      //Serve senator if he is here and acknowledged
      senator.active->Acquire();
      if(senator.state == acknowledged  || senator.state == active){
	senator.active->Release();
	
	printf("%s: senator here, emptying out lines\n", currentThread->getName());
	while(picClerkLine.size() > 0){
	  picClerkLine.removeCustomer();
	}
	while(preferred_picClerkLine.size() > 0){
	  preferred_picClerkLine.removeCustomer();
	}

	//Signal and wait for senator
	printf("%s: emptied lines, waiting for senator\n", currentThread->getName());
	picClerkDesk[myIndex].waitingLine_L->Acquire();
	picClerkDesk[myIndex].state = WaitingOnCustomer;

	// 	if(myIndex == 0){
	// 	  senator.waiting->Signal(senator.active);
	// 	}
	picClerkDesk[myIndex].waiting_Pic->Wait(picClerkDesk[myIndex].waitingLine_L);

	//Interaction with senator
	if(picClerkDesk[myIndex].customerAtDesk)
	  {
	    printf("%s: interacting with senator of ssn %d\n",currentThread->getName(),  appClerkDesk[myIndex].SSN);
	    
	    //ray
	    int randomNum1 = rand()%(102+myIndex);
	    printf("rand num: %d\n",randomNum1);//take this out later
	    if(randomNum1<70){
	      printf("%s: didn't like the picture, retake\n",currentThread->getName());
	    }
	    if(randomNum1<40){
	      printf("%s: didn't like the picture again, retake\n",currentThread->getName());
	    }
	    printf("%s: Satisfied with the picture \n",currentThread->getName());
	    //
	    
	    picClerkDesk[myIndex].customerAtDesk = false;

	    printf("%s: senator picture taken, interaction finished\n",currentThread->getName());
	    //senator.waiting->Signal(senator.active);
	    picClerkDesk[myIndex].waiting_Pic->Signal(picClerkDesk[myIndex].waitingLine_L);
 
	    //Finished interacting with senator, wait until senator is done with passport office
	    picClerkDesk[myIndex].waiting_Pic->Wait(picClerkDesk[myIndex].waitingLine_L);
	  }
	picClerkDesk[myIndex].waitingLine_L->Release();

	//Signaled that the senator is gone.
	//Clerk is ready again
	picClerkDesk[myIndex].state = Ready;
	printf("%s: senator is gone, I am ready to serve customers again\n", currentThread->getName());
	//Continue onto the next loop
	//continue;
      }
      else senator.active->Release();

      //Now serve customers
      picClerkDesk[myIndex].waitingLine_L->Acquire();
      //no customers in the line
      if((picClerkLine.size() == 0) && (preferred_picClerkLine.size() == 0))
	{
	  picClerkDesk[myIndex].waitingLine_L->Release();
	  
	  //Go on break
	  printf("%s: line empty going on break\n",currentThread->getName());
      	  picClerkDesk[myIndex].goingOnBreak->Acquire();
	  picClerkDesk[myIndex].state = OnBreak;
	  picClerkDesk[myIndex].isOccupied = false;
	  picClerkDesk[myIndex].wakeUp->Wait(picClerkDesk[myIndex].goingOnBreak);

	  //Woken up, ready to serve again.
	  picClerkDesk[myIndex].state = Ready;
	  picClerkDesk[myIndex].goingOnBreak->Release();
	  printf("%s: OK, i'm off break, ready to serve customers\n", currentThread->getName());
      
	}
      
      /*if no customer at desk but customers in line and 
	ready then signal next customer*/
      else if(!picClerkDesk[myIndex].customerAtDesk && 
	      preferred_picClerkLine.size() > 0 &&
	      picClerkDesk[myIndex].state == Ready)
	{
	  printf("%s: waiting for preferred customers\n",currentThread->getName());
	  picClerkDesk[myIndex].money += 500;
	  printf("%s: preferred customer paid.  picClerkMoney:%d\n",currentThread->getName(),picClerkDesk[myIndex].money);

	  preferred_picClerkLine.removeCustomer();
	  
	  picClerkDesk[myIndex].state = WaitingOnCustomer;
	  //wait for customer to come to desk, does not have to be signaled customer
	  picClerkDesk[myIndex].waiting_Pic->Wait(picClerkDesk[myIndex].waitingLine_L);

	  //if first customer from line picks this clerk
	  if(picClerkDesk[myIndex].customerAtDesk)
	    {
	      printf("%s: interacting with customer of ssn %d\n",currentThread->getName(),  picClerkDesk[myIndex].SSN);
	   
	      //ray
	      int randomNum1 = rand()%(102+myIndex);
	      printf("rand num: %d\n",randomNum1);//take this out later
	       
	      if(randomNum1<70){
		printf("%s: didn't like the picture, retake\n",currentThread->getName());
	      }
	      if(randomNum1<40){
		printf("%s: didn't like the picture again, retake\n",currentThread->getName());
	      }
	      printf("%s: Satisfied with the picture \n",currentThread->getName());
	      //
	       
	      //do randome yield here
	      picClerkDesk[myIndex].customerAtDesk = false;
	      printf("%s: customer interaction finished\n",currentThread->getName());
	      //wake current customer back up
	      picClerkDesk[myIndex].waiting_Pic->Signal(picClerkDesk[myIndex].waitingLine_L);
	       
	      //FILE CODE:
	      int fileTime = (rand()%80) + 20;
	      for (int i = 0; i < fileTime; i++)
		{
		  currentThread->Yield();
		}
	       
	      //find available slot to file ssn
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  picOK_L.Acquire();

		  if(picOK[i] == LARGENUMBER)
		    {
		      picOK[i] =   picClerkDesk[myIndex].SSN;
		      i = MAXCUSTOMERS; //now exit
		    }
		  picOK_L.Release();
		}

	      printf("%s: after yielding %d times, picture filed for customer of ssn %d\n",currentThread->getName(),fileTime, picClerkDesk[myIndex].SSN);
	    }
	   
	  picClerkDesk[myIndex].state = Ready;
	  picClerkDesk[myIndex].waitingLine_L->Release();
	   
	}
       
      /*if no customer at desk but customers in line and 
	ready then signal next customer*/
      else if(!picClerkDesk[myIndex].customerAtDesk && 
	      picClerkLine.size() > 0 &&
	      picClerkDesk[myIndex].state == Ready)
	{
	  printf("%s: waiting for customers\n",currentThread->getName());
	  picClerkLine.removeCustomer();
	  
	  picClerkDesk[myIndex].state = WaitingOnCustomer;
	  //wait for customer to come to desk, does not have to be signaled customer
	  picClerkDesk[myIndex].waiting_Pic->Wait(picClerkDesk[myIndex].waitingLine_L);

	  //if first customer from line picks this clerk
	  if(picClerkDesk[myIndex].customerAtDesk)
	    {
	      printf("%s: interacting with customer of ssn %d\n",currentThread->getName(),  picClerkDesk[myIndex].SSN);
	   
	      //ray
	      int randomNum1 = rand()%(102+myIndex);
	      printf("rand num: %d\n",randomNum1);//take this out later
	       
	      if(randomNum1<70){
		printf("%s: didn't like the picture, retake\n",currentThread->getName());
	      }
	      if(randomNum1<40){
		printf("%s: didn't like the picture again, retake\n",currentThread->getName());
	      }
	      printf("%s: Satisfied with the picture \n",currentThread->getName());
	      //
	       
	      picClerkDesk[myIndex].customerAtDesk = false;
	      printf("%s: customer  of ssn %d interaction finished\n",currentThread->getName(), picClerkDesk[myIndex].SSN);
	      //wake current customer back up
	      picClerkDesk[myIndex].waiting_Pic->Signal(picClerkDesk[myIndex].waitingLine_L);
	       
	      //FILE CODE:
	      int fileTime = (rand()%80) + 20;
	      for (int i = 0; i < fileTime; i++)
		{
		  currentThread->Yield();
		}
	       
	      //find available slot to file ssn
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  picOK_L.Acquire();

		  if(picOK[i] == LARGENUMBER)
		    {
		      picOK[i] =   picClerkDesk[myIndex].SSN;
		      i = MAXCUSTOMERS; //now exit
		    }
		  picOK_L.Release();
		}

	      printf("%s: after yielding %d times, picture filed for customer of ssn %d\n",currentThread->getName(),fileTime, picClerkDesk[myIndex].SSN);
	    }
	   
	  picClerkDesk[myIndex].state = Ready;
	  picClerkDesk[myIndex].waitingLine_L->Release();
	   
	}
      
      else 
	{
	  picClerkDesk[myIndex].waitingLine_L->Release();
	  printf("%s: error found nothing to do!\n",currentThread->getName());
	}
    }
      
}






/*
  ----------------------------------------------
  *
  *          PASSPORT CLERK:
  *
  ----------------------------------------------
*/

int nextPassClerkIndex = 0;

void PassportClerk()
{
  printf("Passport Clerk Thread %s is made and currently running\n",currentThread->getName());
  
  int myIndex = nextPassClerkIndex;
  nextPassClerkIndex++;

  passClerkDesk[myIndex];
  //initialize my values 
  passClerkDesk[myIndex].waitingLine_L = new Lock("waiting line_L");
  passClerkDesk[myIndex].waiting_App = new Condition("waiting_App");

  passClerkDesk[myIndex].goingOnBreak = new Lock("Going on Break");
  passClerkDesk[myIndex].wakeUp = new Condition("wake Up");

  passClerkDesk[myIndex].waitingLine_L->Acquire();

  passClerkDesk[myIndex].money = 0;
  passClerkDesk[myIndex].state = Ready;
  passClerkDesk[myIndex].SSN = LARGENUMBER;
  passClerkDesk[myIndex].customerAtDesk = false;
  passClerkDesk[myIndex].isOccupied = true;

  printf("%s: initialized with array index %d and waiting for customers\n",currentThread->getName(),myIndex);

  //wait until a cutstomer arrives
  //passClerkDesk[myIndex].waiting_App->Wait(passClerkDesk[myIndex].waitingLine_L);
  passClerkDesk[myIndex].waitingLine_L->Release();

  //main waiting on customers loop
  while(true)
    {
      //Serve senator if he is here and acknowledged
      senator.active->Acquire();
      if(senator.state == acknowledged || senator.state == active){
	senator.active->Release();

	printf("%s: senator here, emptying out lines\n", currentThread->getName());
	while(passClerkLine.size() > 0){
	  passClerkLine.removeCustomer();
	}
	while(preferred_passClerkLine.size() > 0){
	  preferred_passClerkLine.removeCustomer();
	}

	//Signal and wait for senator
	printf("%s: emptied lines, waiting for senator\n", currentThread->getName());
	passClerkDesk[myIndex].waitingLine_L->Acquire();
	passClerkDesk[myIndex].state = WaitingOnCustomer;

	// 	if(myIndex == 0){
	// 	  senator.waiting->Signal(senator.active);
	// 	}
	passClerkDesk[myIndex].waiting_App->Wait(passClerkDesk[myIndex].waitingLine_L);

	//Interaction with senator
	if(passClerkDesk[myIndex].customerAtDesk)
	  {
	    printf("%s: interacting with senator of ssn %d\n",currentThread->getName(),  appClerkDesk[myIndex].SSN);
	    
	    passClerkDesk[myIndex].customerAtDesk = false;

	    printf("%s: senator passport approved, finished interaction\n",currentThread->getName());
	    //senator.waiting->Signal(senator.active);
	    passClerkDesk[myIndex].waiting_App->Signal(passClerkDesk[myIndex].waitingLine_L);

	    //Finished interacting with senator, wait until senator is done with passport office
	    passClerkDesk[myIndex].waiting_App->Wait(passClerkDesk[myIndex].waitingLine_L);
	  }
	passClerkDesk[myIndex].waitingLine_L->Release();

	//Signaled that the senator is gone.
	//Clerk is ready again
	passClerkDesk[myIndex].state = Ready;
	printf("%s: senator is gone, I am ready to serve customers again\n", currentThread->getName());
	//Continue onto the next loop
	//continue;
      }
      else senator.active->Release();

      //Serve customers now
      passClerkDesk[myIndex].waitingLine_L->Acquire();
      //no customers in the line
      if((passClerkLine.size() == 0) && (preferred_passClerkLine.size() == 0))
	{
	  passClerkDesk[myIndex].waitingLine_L->Release();
	  
	  //Go on break
	  printf("%s: line empty going on break\n",currentThread->getName());
      	  passClerkDesk[myIndex].goingOnBreak->Acquire();
	  passClerkDesk[myIndex].state = OnBreak;
	  passClerkDesk[myIndex].isOccupied = false;
	  passClerkDesk[myIndex].wakeUp->Wait(passClerkDesk[myIndex].goingOnBreak);

	  //Woken up, ready to serve again.
	  passClerkDesk[myIndex].state = Ready;
	  passClerkDesk[myIndex].goingOnBreak->Release();
	  printf("%s: OK, i'm off break, ready to serve customers\n", currentThread->getName());
	 
      
	}

      else if(!passClerkDesk[myIndex].customerAtDesk && 
	      preferred_passClerkLine.size() > 0 &&
	      passClerkDesk[myIndex].state == Ready)
	{
	  printf("%s: waiting for preferred customers\n",currentThread->getName());
	  passClerkDesk[myIndex].money += 500;
	  printf("%s: preferred customer paid.  passClerkMoney:%d\n",currentThread->getName(),passClerkDesk[myIndex].money);
	  preferred_passClerkLine.removeCustomer();
	  
	  passClerkDesk[myIndex].state = WaitingOnCustomer;
	  //wait for customer to come to desk, does not have to be signaled customer
	  passClerkDesk[myIndex].waiting_App->Wait(passClerkDesk[myIndex].waitingLine_L);

	  //if first customer from line picks this clerk
	  if(passClerkDesk[myIndex].customerAtDesk)
	    {
	      printf("%s: interacting with customer of ssn %d\n",currentThread->getName(),  passClerkDesk[myIndex].SSN);
	      //file passport after signal and put ssn just in first open slot in array
	      //delete picture and app slots 
	      //keep checking that customer picture and application are done
	      bool passIsAGo = false;
	      while(!passIsAGo)
		{
		  //check application first
		  for(int i = 0; i < MAXCUSTOMERS && !passIsAGo; i++)
		    {
		      if(appOK[i] == passClerkDesk[myIndex].SSN)
			{
			  for(int j = 0; j < MAXCUSTOMERS && !passIsAGo; j++)
			    {
			      if(picOK[j] == passClerkDesk[myIndex].SSN)
				{
				  passIsAGo = true;
				}
			    }
			}
		    }

		  currentThread->Yield();
		}
			  

	      printf("%s: preferred customer of ssn %d interaction finished passport created\n",currentThread->getName(),passClerkDesk[myIndex].SSN);	      
	      passClerkDesk[myIndex].customerAtDesk = false;
	      //wake current customer back up
	      passClerkDesk[myIndex].waiting_App->Signal(passClerkDesk[myIndex].waitingLine_L);
	      //FILE CODE:
	      int fileTime = (rand()%80) + 20;
	      for (int i = 0; i < fileTime; i++)
		{
		  currentThread->Yield();
		}
	       
	      //find available slot to file ssn
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  passOK_L.Acquire();

		  if(passOK[i] == LARGENUMBER)
		    {
		      passOK[i] =   passClerkDesk[myIndex].SSN;
		      i = MAXCUSTOMERS; //now exit
		    }
		  passOK_L.Release();
		}
	       
	      //registered passport and now free up space in other arrays
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  appOK_L.Acquire();

		  if(appOK[i] ==  passClerkDesk[myIndex].SSN)
		    {
		      appOK[i] = LARGENUMBER;//effectively empty
		      i = MAXCUSTOMERS;
		    }
		  appOK_L.Release();
		}
		
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  appOK_L.Acquire();

		  if(picOK[i] ==  passClerkDesk[myIndex].SSN)
		    {
		      picOK[i] =  LARGENUMBER;//effectively empty  
		      i = MAXCUSTOMERS; //now exit
		    }
		  appOK_L.Release();
		}
		
		
	      printf("%s: after yielding %d times, passport filed for customer of ssn %d\n",currentThread->getName(),fileTime, passClerkDesk[myIndex].SSN);
	     
	    }
	   
	  passClerkDesk[myIndex].state = Ready;
	  passClerkDesk[myIndex].waitingLine_L->Release();
	   
	}      


      /*if no customer at desk but customers in line and 
	ready then signal next customer*/
      else if(!passClerkDesk[myIndex].customerAtDesk && 
	      passClerkLine.size() > 0 &&
	      passClerkDesk[myIndex].state == Ready)
	{
	  printf("%s: waiting for customers\n",currentThread->getName());
	  passClerkLine.removeCustomer();
	  
	  passClerkDesk[myIndex].state = WaitingOnCustomer;
	  //wait for customer to come to desk, does not have to be signaled customer
	  passClerkDesk[myIndex].waiting_App->Wait(passClerkDesk[myIndex].waitingLine_L);
	  

	  //if first customer from line picks this clerk
	  if(passClerkDesk[myIndex].customerAtDesk)
	    {
	      printf("%s: interacting with customer of ssn %d\n",currentThread->getName(),  passClerkDesk[myIndex].SSN);
	   
	      //file passport after signal and put ssn just in first open slot in array
	      //delete picture and app slots 
	      //keep checking that customer picture and application are done
	      bool passIsAGo = false;
	       
	      while(!passIsAGo)
		{
		   
		  //check application first
		  for(int i = 0; i < MAXCUSTOMERS && !passIsAGo; i++)
		    {
		      if(appOK[i] == passClerkDesk[myIndex].SSN)
			{
			  for(int j = 0; j < MAXCUSTOMERS && !passIsAGo; j++)
			    {
			      if(picOK[j] == passClerkDesk[myIndex].SSN)
				{
				  passIsAGo = true;
				}
			    }
			}
		    }
		  //printf("RECORD NOT FOUND!");
		  currentThread->Yield();
		}
	       
	      
	      printf("%s: customer of ssn %d interaction finished passport created\n",currentThread->getName(),passClerkDesk[myIndex].SSN);
	      passClerkDesk[myIndex].customerAtDesk = false;
	      //wake current customer back up
	      passClerkDesk[myIndex].waiting_App->Signal(passClerkDesk[myIndex].waitingLine_L);
	      //FILE CODE:
	      int fileTime = (rand()%80) + 20;
	      for (int i = 0; i < fileTime; i++)
		{
		  currentThread->Yield();
		}
	       
	      //find available slot to file ssn
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  passOK_L.Acquire();

		  if(passOK[i] == LARGENUMBER)
		    {
		      passOK[i] =   passClerkDesk[myIndex].SSN;
		      i = MAXCUSTOMERS; //now exit
		    }
		  passOK_L.Release();
		}
	       
	      //registered passport and now free up space in other arrays
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  appOK_L.Acquire();

		  if(appOK[i] ==  passClerkDesk[myIndex].SSN)
		    {
		      appOK[i] = LARGENUMBER;//effectively empty
		      i = MAXCUSTOMERS;
		    }
		  appOK_L.Release();
		}
		
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  appOK_L.Acquire();

		  if(picOK[i] ==  passClerkDesk[myIndex].SSN)
		    {
		      picOK[i] =  LARGENUMBER;//effectively empty  
		      i = MAXCUSTOMERS; //now exit
		    }
		  appOK_L.Release();
		}
		
		
	      printf("%s: after yielding %d times, passport filed for customer of ssn %d\n",currentThread->getName(),fileTime, passClerkDesk[myIndex].SSN);
	     

	    }
	   
	  passClerkDesk[myIndex].state = Ready;
	  passClerkDesk[myIndex].waitingLine_L->Release();
	   
	}
      
      else 
	{
	  passClerkDesk[myIndex].waitingLine_L->Release();
	  printf("%s: error found nothing to do!\n",currentThread->getName());
	}
    }
      
}
	     

  








/*
  ----------------------------------------------
  *
  *           CASHIER CODE:
  *
  ----------------------------------------------
*/


int nextCashierClerkIndex = 0;

void CashierClerk()
{
  printf("Cashier Thread %s is made and currently running\n",currentThread->getName());
  
  int myIndex = nextCashierClerkIndex;
  nextCashierClerkIndex++;
  
  cashierDesk[myIndex];
  //initialize my values 
  cashierDesk[myIndex].waitingLine_L = new Lock("waiting line_L");
  cashierDesk[myIndex].waiting_App = new Condition("waiting_App");

  cashierDesk[myIndex].goingOnBreak = new Lock("Going on Break");
  cashierDesk[myIndex].wakeUp = new Condition("wake Up");

  cashierDesk[myIndex].waitingLine_L->Acquire();

  cashierDesk[myIndex].money = 0;
  cashierDesk[myIndex].passState = empty;
  cashierDesk[myIndex].state = Ready;
  cashierDesk[myIndex].SSN = LARGENUMBER;
  cashierDesk[myIndex].customerAtDesk = false;
  cashierDesk[myIndex].isOccupied = true;

  printf("%s: initialized with array index %d and waiting for customers\n",currentThread->getName(),myIndex);

  //wait until a cutstomer arrives
  //cashierDesk[myIndex].waiting_App->Wait(cashierDesk[myIndex].waitingLine_L);
  cashierDesk[myIndex].waitingLine_L->Release();

  //main waiting on customers loop
  while(true)
    { 
      //Serve senator if he is here and acknowledged
      senator.active->Acquire();
      if(senator.state == acknowledged || senator.state == active){
	senator.active->Release();

	printf("%s: senator here, emptying out lines\n", currentThread->getName());
	while(cashierLine.size() > 0){
	  cashierLine.removeCustomer();
	}
	while(preferred_cashierLine.size() > 0){
	  preferred_cashierLine.removeCustomer();
	}

	//Signal and wait for senator
	printf("%s: emptied lines, waiting for senator\n", currentThread->getName());
	cashierDesk[myIndex].waitingLine_L->Acquire();
	cashierDesk[myIndex].state = WaitingOnCustomer;


	cashierDesk[myIndex].waiting_App->Wait(cashierDesk[myIndex].waitingLine_L);

	//Interaction with senator
	if(cashierDesk[myIndex].customerAtDesk)
	  {
	    cashierDesk[myIndex].money += 100;
	    printf("%s: interacting with senator of ssn %d\n",currentThread->getName(),  appClerkDesk[myIndex].SSN);
	    
	    cashierDesk[myIndex].customerAtDesk = false;

	    printf("%s: gave passport to senator, interaction finished\n",currentThread->getName());
	    //senator.waiting->Signal(senator.active);
	    cashierDesk[myIndex].waiting_App->Signal(cashierDesk[myIndex].waitingLine_L);

	    //Finished interacting with senator, wait until senator is done with passport office
	    cashierDesk[myIndex].waiting_App->Wait(cashierDesk[myIndex].waitingLine_L);
	  }
	cashierDesk[myIndex].waitingLine_L->Release();

	//Signaled that the senator is gone.
	//Clerk is ready again
	cashierDesk[myIndex].state = Ready;
	printf("%s: senator is gone, I am ready to serve customers again\n", currentThread->getName());
	//Continue onto the next loop
	//continue;
      }
      else senator.active->Release();

      //Serve Customers now
      cashierDesk[myIndex].waitingLine_L->Acquire();

      //reset the passport to default value
      cashierDesk[myIndex].passState = empty;

      //no customers in the line
      if((cashierLine.size() == 0) && (preferred_cashierLine.size() == 0))
	{
	  cashierDesk[myIndex].waitingLine_L->Release();
	  
	  //Go on break
	  printf("%s: line empty going on break\n",currentThread->getName());
      	  cashierDesk[myIndex].goingOnBreak->Acquire();
	  cashierDesk[myIndex].state = OnBreak;
	  cashierDesk[myIndex].isOccupied = false;
	  cashierDesk[myIndex].wakeUp->Wait(cashierDesk[myIndex].goingOnBreak);

	  //Woken up, ready to serve again.
	  cashierDesk[myIndex].state = Ready;
	  cashierDesk[myIndex].goingOnBreak->Release();
	  printf("%s: OK, i'm off break, ready to serve customers\n", currentThread->getName());
	  
      
	}
      

      else if(!cashierDesk[myIndex].customerAtDesk && 
	      preferred_cashierLine.size() > 0 &&
	      cashierDesk[myIndex].passState == empty &&
	      cashierDesk[myIndex].state == Ready)
	{
	  printf("%s: waiting for preferred customers\n",currentThread->getName());
	  cashierDesk[myIndex].money += 600;
	  printf("%s: preferred customer paid.  cashierMoney:%d\n",currentThread->getName(),cashierDesk[myIndex].money);
	  preferred_cashierLine.removeCustomer();
	  
	  cashierDesk[myIndex].state = WaitingOnCustomer;
	  //wait for customer to come to desk, does not have to be signaled customer
	  cashierDesk[myIndex].waiting_App->Wait(cashierDesk[myIndex].waitingLine_L);

	  //if first customer from line picks this clerk
	  if(cashierDesk[myIndex].customerAtDesk)
	    {
	      printf("%s: interacting with customer of ssn %d\n",currentThread->getName(),  cashierDesk[myIndex].SSN);
	    


	      /*as stated in the requirement, here we are making sure that multiple passports cannot be handed out to the same customer*/
	       bool passExists = false;
	       passDone_L.Acquire();

	       for(int i = 0; i < MAXCUSTOMERS && !passExists; i++)
		 {
		   if(cashierDesk[myIndex].SSN == passDone[i])
		     {
		       passExists = true;
		     }
		 }
	       
	       passDone_L.Release();

   
	      cashierDesk[myIndex].passState = rejected;
	      //check for customer approved passport 
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  passOK_L.Acquire();

		  if(passOK[i] == LARGENUMBER)
		    {
		      passOK[i] = passClerkDesk[myIndex].SSN;
		      cashierDesk[myIndex].passState = approved;
		      
		      passDone_L.Acquire();
		   
		     
		        /*find empty slot to record that this
			customer was given a passport*/
		      for(int j = 0; j < MAXCUSTOMERS; j++)
			{
			  if(passDone[j] == LARGENUMBER)
			    {
			      passDone[j] =  cashierDesk[myIndex].SSN;
			    }
			}
		   
		      passDone_L.Release();
		       
		      //free up array slot
		      for(int j = 0; j < MAXCUSTOMERS;j++)
			{

			  if(passOK[j] ==  passClerkDesk[myIndex].SSN)
			    {
			      passOK[j] = LARGENUMBER;//effectively empty
			      j = MAXCUSTOMERS;
			    }
			}

		       
		      i = MAXCUSTOMERS; //now exit
		    }


		  passOK_L.Release();
		}

	      

	      cashierDesk[myIndex].customerAtDesk = false;
	      printf("%s: customer interaction finished\n",currentThread->getName());
	      //wake current customer back up
	      cashierDesk[myIndex].waiting_App->Signal(cashierDesk[myIndex].waitingLine_L);
	    }
	   
	  cashierDesk[myIndex].state = Ready;
	  cashierDesk[myIndex].waitingLine_L->Release();
	   
	}

      /*if no customer at desk but customers in line and 
	ready then signal next customer*/
      else if(!cashierDesk[myIndex].customerAtDesk && 
	      cashierLine.size() > 0 &&
	      cashierDesk[myIndex].passState == empty &&
	      cashierDesk[myIndex].state == Ready)
	{
	  printf("%s: waiting for customers\n",currentThread->getName());
	  cashierDesk[myIndex].money += 100;
	  cashierLine.removeCustomer();
	  
	  cashierDesk[myIndex].state = WaitingOnCustomer;
	  //wait for customer to come to desk, does not have to be signaled customer
	  cashierDesk[myIndex].waiting_App->Wait(cashierDesk[myIndex].waitingLine_L);

	  //if first customer from line picks this clerk
	  if(cashierDesk[myIndex].customerAtDesk)
	    {
	      printf("%s: interacting with customer of ssn %d\n",currentThread->getName(),  cashierDesk[myIndex].SSN);
	       
	     

	        /*as stated in the requirement, here we are making 
		  sure that multiple passports cannot be handed out 
		  to the same customer.*/
	       bool passExists = false;
	       passDone_L.Acquire();

	       for(int i = 0; i < MAXCUSTOMERS && !passExists; i++)
		 {
		   if(cashierDesk[myIndex].SSN == passDone[i])
		     {
		       passExists = true;
		     }
		 }
	       
	       passDone_L.Release();
	      
	      
	      cashierDesk[myIndex].passState = rejected;
	      //check for customer approved passport 
	      for(int i = 0; i < MAXCUSTOMERS;i++)
		{
		  //acquire/release here so maybe less thread sleeping
		  passOK_L.Acquire();

		  if(passOK[i] == LARGENUMBER)
		    {
		      passOK[i] = passClerkDesk[myIndex].SSN;
		      cashierDesk[myIndex].passState = approved;
		      
		        passDone_L.Acquire();
		   
		      /*find empty slot to record that this
			customer was given a passport*/
		      for(int j = 0; j < MAXCUSTOMERS; j++)
			{
			  if(passDone[j] == LARGENUMBER)
			    {
			      passDone[j] =  cashierDesk[myIndex].SSN;
			    }
			}
		   
		      passDone_L.Release();
		       
		      //free up array slot
		      for(int j = 0; j < MAXCUSTOMERS;j++)
			{

			  if(passOK[j] ==  passClerkDesk[myIndex].SSN)
			    {
			      passOK[j] = LARGENUMBER;//effectively empty
			      j = MAXCUSTOMERS;
			    }
			}



		      i = MAXCUSTOMERS; //now exit
		    }


		  passOK_L.Release();
		}

	      cashierDesk[myIndex].customerAtDesk = false;
	      printf("%s: customer interaction finished\n",currentThread->getName());
		
	      //wake current customer back up
	      cashierDesk[myIndex].waiting_App->Signal(cashierDesk[myIndex].waitingLine_L);
	    }
	   
	  cashierDesk[myIndex].state = Ready;
	  cashierDesk[myIndex].waitingLine_L->Release();
	   
	}
      
      else 
	{
	  cashierDesk[myIndex].waitingLine_L->Release();
	  printf("%s: error found nothing to do!\n",currentThread->getName());
	}
       }
      
}






/*
  ----------------------------------------------
  *
  *           CUSTOMER CODE:
  *
  ----------------------------------------------
*/




/*function to find avaiable clerk of a certian type
  to interact with
  return: bool indicating if any of that type are 
  avaiable at all
  key here that data is controled by a condition
  variable and thus given up by clerk or customer 
  during interaction or else we might go to 
  sleep each time we try to check a clerk status*/
bool  findAvailableClerk(ClerkType clerkType, int ssn)
{
  //check the clerks state and wake one up

  if(clerkType == application)
    {
      for(int i = 0; i <  nextAppClerkIndex; i++)
	{
	  appClerkDesk[i].waitingLine_L->Acquire();

	  if(appClerkDesk[i].state == WaitingOnCustomer)
	    {
	      printf("%s%d: waiting at application clerk desk of index %d\n",currentThread->getName(),ssn,i);
	      appClerkDesk[i].customerAtDesk = true;
	      appClerkDesk[i].SSN = ssn;
	      appClerkDesk[i].state = Busy;

	      /*wait (in wait releasing the lock) clerk does wake up
		clerk files stuff then wakes customer up */
	      appClerkDesk[i].waiting_App->Signal(appClerkDesk[i].waitingLine_L);
	      appClerkDesk[i].waiting_App->Wait(appClerkDesk[i].waitingLine_L);

	      appClerkDesk[i].waitingLine_L->Release();
	      //interaction over,nothing more to do
	      printf("%s%d: finished with application clerk of index %d\n",currentThread->getName(),ssn,i);
	      return true;
	    }
	 
	  appClerkDesk[i].waitingLine_L->Release();
	 
	}
    }
  
  if(clerkType == picture)
    {
      for(int i = 0; i <  nextPicClerkIndex; i++)
	{
	  picClerkDesk[i].waitingLine_L->Acquire();
	  
	  if(picClerkDesk[i].state == WaitingOnCustomer)
	    {
	      printf("%s%d: waiting at picture clerk desk of index %d\n",currentThread->getName(),ssn,i);
	      picClerkDesk[i].customerAtDesk = true;
	      picClerkDesk[i].SSN = ssn;
	      picClerkDesk[i].state = Busy;
	      
	      /*wait (in wait releasing the lock) clerk does wake up
		clerk files stuff then wakes customer up */
	      picClerkDesk[i].waiting_Pic->Signal(picClerkDesk[i].waitingLine_L);
	      picClerkDesk[i].waiting_Pic->Wait(picClerkDesk[i].waitingLine_L);
	      
	      picClerkDesk[i].waitingLine_L->Release();
	      
	      
	      //interaction over,nothing more to do
	      printf("%s%d: finished with picture clerk of index %d\n",currentThread->getName(),ssn,i);
	      return true;
	    }
	  
	  picClerkDesk[i].waitingLine_L->Release();
	  
	}
    }


  if(clerkType == passport)
    {
      for(int i = 0; i <  nextPassClerkIndex; i++)
	{
	  passClerkDesk[i].waitingLine_L->Acquire();

	  if(passClerkDesk[i].state == WaitingOnCustomer)
	    {
	      printf("%s%d: waiting at passport clerk desk of index %d\n",currentThread->getName(),ssn,i);
	      passClerkDesk[i].customerAtDesk = true;
	      passClerkDesk[i].SSN = ssn;
	      passClerkDesk[i].state = Busy;

	      /*wait (in wait releasing the lock) clerk does wake up
		clerk files stuff then wakes customer up */
	      passClerkDesk[i].waiting_App->Signal(passClerkDesk[i].waitingLine_L);
	      passClerkDesk[i].waiting_App->Wait(passClerkDesk[i].waitingLine_L);

	      passClerkDesk[i].waitingLine_L->Release();
	      
	      //interaction over,nothing more to do
	      printf("%s%d: finished with passport clerk of index %d\n",currentThread->getName(),ssn,i);
	      return true;
	    }
	  
	  passClerkDesk[i].waitingLine_L->Release();
	 
	}
    }

  if(clerkType == cashier)
    {
      for(int i = 0; i <  nextCashierClerkIndex; i++)
	{
	  cashierDesk[i].waitingLine_L->Acquire();

	  if(cashierDesk[i].state == WaitingOnCustomer &&  
	     cashierDesk[i].passState == empty)
	    {
	      printf("%s%d: waiting at cashier desk of index %d\n",currentThread->getName(),ssn ,i);
	      cashierDesk[i].customerAtDesk = true;
	      cashierDesk[i].SSN = ssn;
	      cashierDesk[i].state = Busy;

	      /*wait (in wait releasing the lock) clerk does wake up
		clerk files stuff then wakes customer up */
	      cashierDesk[i].waiting_App->Signal(cashierDesk[i].waitingLine_L);
	      cashierDesk[i].waiting_App->Wait(cashierDesk[i].waitingLine_L);
	      
	      //check if passport was filed yet
	      if(cashierDesk[i].passState == rejected)
		{
		  cashierDesk[i].passState = empty;//reset state
		  
		  //punish self with yield() and try again
		  printf("%s%d: got to cashier too earlier\n",currentThread->getName(),ssn);
		  int timeOutTime = (rand()%900) + 100;
		  for(int j = 0; j < timeOutTime; j++)
		    {
		      currentThread->Yield();
		    }
		  cashierDesk[i].waitingLine_L->Release();
		  cashierLine.addCustomer();  

		  
		}
	      else//we are done
		{
		  cashierDesk[i].passState = empty;//reset state
		  cashierDesk[i].money += 100;
		   
		}
	    
	      cashierDesk[i].waitingLine_L->Release();
	      
	      //interaction over,nothing more to do
	      printf("%s%d: finished with cashier of index %d\n",currentThread->getName(),ssn,i);
	      return true;
	    }
	 
	  cashierDesk[i].waitingLine_L->Release();
	 
	}
    }
  //if no passport clerks available yet, keep checking 
    
  //give cpu to other threads then try again
  
  return false;
}


  
 

int nextSSN = 0;

void CustomerMainLoop()
{

  //Variables for customer
  CustomerState state = created;
  ClerkType currentClerk = none;
  int ssn = nextSSN;
  nextSSN++;

  printf("Thread %s%d is made and currently running\n",currentThread->getName(),ssn);

  int custMoney;
  int a = (rand()+ssn)%4;
  if(a == 0){
    custMoney = 100;
  }
  else if(a == 1){
    custMoney = 600;
  }
  else if(a == 2){
    custMoney = 1100;
  }
  else if(a == 3){
    custMoney = 1600;
  }


  printf("%s%d: custMoney is %d\n",currentThread->getName(),ssn, custMoney);
  //total line cycle happens 4 times
  for (int i = 0; i < 4; i++)
    {
      
     

      /*set state first because after PlaceMeInLine()
	customer will be asleep in line*/
      state = waitingInLine;
      custMoney = PlaceMeInLine(&currentClerk,custMoney,ssn);
  
      //NOTE:ADD CUTTING PAYMENT PART 
      /*clerk interaction: customer picks 
	the first clerk of this type available  */
      state = atDesk;
      printf("%s%d:finding available clerk\n",currentThread->getName(),ssn);
      findAvailableClerk(currentClerk,ssn);    
	 
      if(i == 0) //at first picture or app clerk
	{
	  if(currentClerk == application)
	    {
	      currentClerk = picture;
	    }

	  else 
	    {
	      currentClerk = application;
	    }
	    
	}
      
      //NOTE CHANGE THIS AFTER ADDING PICTURE CLERK
      if(i == 1)
	{
	  currentClerk = passport;
	}

      if(i == 2)
	{
	  printf("%s%d: custMoney before cashier is %d\n",currentThread->getName(),ssn, custMoney);
	  currentClerk = cashier;
	}
      
    

    }
  
  printf("%s%d: finished with passport office!\n",currentThread->getName(),ssn);
  printf("%s%d: MONEY LEFT = %d\n",currentThread->getName(),ssn,custMoney);
  
  totalCust--;
}

/*
  -------------------------------
  *
  * SENATOR MAIN CODE
  *
  ------------------------------
*/

/*
  Senator will first set his state to waiting.
  Then he will go to sleep.  When the manager is called,
  and he finds the senator, he will change the senator 
  state to acknolwedged, and he will also make sure that
  one of each clerk is awake.  Then, when the clerks
  finished serving their last customer, will check for 
  the senator state.  And upon seeing his state as
  asknowledged, they will remove and make a copy of 
  the existing customer line. After, all the clerks 
  except for the app clerk will go to sleep, waiting
  to be awakened by the senator.  The App clerk however
  will change the senator state to active and signal
  the senator that everyone is ready.  The senator will
  then go by each clerk one by one in a sequential order
  to get his passport filed.  After each clerk is done,
  the clerks will go to sleep again.  At the end, when
  the senator is done, he will change his state to finished
  and signal all the clerks that he is finished.
*/
int senatorSSN = 800;

void SenatorMainLoop(){
  int ssn = senatorSSN++;
  ClerkType clerktype;

  senator.active->Acquire();

  //Waiting for clerks to signal me when they are ready
  printf("%s: I have come into the passport office, now waiting\n", currentThread->getName());
  senator.state = waiting;
  senator.waiting->Wait(senator.active);

  //Begin requesting clerk services
  senator.state = active;
  printf("%s: Looks like passport office is ready\n", currentThread->getName());
  senator.active->Release();

  //App Clerk
  clerktype = application;
  findAvailableClerk(clerktype, ssn);

  //Pic Clerk
  clerktype = picture;
  findAvailableClerk(clerktype, ssn);

  //Passport Clerk
  clerktype = passport;
  findAvailableClerk(clerktype, ssn);

  //Cashier
  clerktype = cashier;
  findAvailableClerk(clerktype, ssn);

  //Senator is finished

  senator.active->Acquire();
  senator.state = finished;
  senator.active->Release();
  printf("%s: Got my passport, I am finished now.\n", currentThread->getName());
}

void senatorIsHere(){
  Thread *t = new Thread("Senator");
  t->Fork((VoidFunctionPtr)SenatorMainLoop,0);
}


/*
  -------------------------------
  *
  * PROGRAM TERMINATION CODE
  *
  * Basically, when there are two or less people in each line
  * and when all the clerks are on break, then the program
  * will not be able to continue on any further.  
  * Thus we will terminate the program at that point.
  ------------------------------
*/


void Finished(){

  //Check that there are two or less people in each line
  printf("totalCust: %d\n",totalCust);
  
  if((appClerkLine.size()+preferred_appClerkLine.size()) == 0 && (picClerkLine.size()+preferred_picClerkLine.size()) == 0 && (passClerkLine.size()+preferred_passClerkLine.size()) == 0 && (cashierLine.size()+preferred_cashierLine.size()) == 0 && totalCust == 0){
    

    for(int i = 0; i<nextAppClerkIndex; i++){
      appClerkDesk[i].waitingLine_L->Acquire();
      if(appClerkDesk[i].state != OnBreak){
	appClerkDesk[i].waitingLine_L->Release();
	return;
      }
      appClerkDesk[i].waitingLine_L->Release();
    }

    for(int i = 0; i<nextPicClerkIndex; i++){
      picClerkDesk[i].waitingLine_L->Acquire();
      if(picClerkDesk[i].state != OnBreak){
	picClerkDesk[i].waitingLine_L->Release();
	return;
      }
      picClerkDesk[i].waitingLine_L->Release();
    }

    for(int i = 0; i<nextPassClerkIndex; i++){
      passClerkDesk[i].waitingLine_L->Acquire();
      if(passClerkDesk[i].state != OnBreak){
	passClerkDesk[i].waitingLine_L->Release();
	return;
      }
      passClerkDesk[i].waitingLine_L->Release();
    }

    for(int i=0; i<nextCashierClerkIndex; i++){
      cashierDesk[i].waitingLine_L->Acquire();
      if(cashierDesk[i].state != OnBreak){
	cashierDesk[i].waitingLine_L->Release();
	return;
      }
      cashierDesk[i].waitingLine_L->Release();
    }
    
    printf("\nPROGRAM REACHED END, WILL NOW TERMINATE\n");
    printf("(No customer in line and all clerks are on break.  Terminate the program.)\n");
    Exit(0);
    

  }


}


/*
  -------------------------------
  *
  * MANAGER MAIN CODE
  *
  ------------------------------
*/

/*
  MANAGER MAIN LOOP:
  Using a timer thread to call.  It will check the line size,
  and wake up any clerk necessary.  It will also get the money 
  earned from each clerk, and total up the clerk type.
  
  In order for the clerk on break scenario to work, the clerk
  must go to sleep through a c.v.  Then the manager will signal
  the clerk.
  
  Timer thread also disables all interrupts when the function is
  called.  Thus no acquire/release is needed.
*/

//Using a timer loop to run the manager, and it fires too fast.
//Thus using an int to skip every number time before executing
int manager_runtime = 0; //How many times called
int manager_freq = 70; //Frequency to run
bool test2doit = false;
int test2money = 0;
bool test2access = true;//for test 1: goes to false when one manager loop completes
bool test6doit = false;
int test6money = 0;

//Main Loop of the manager logic
void ManagerMainLoop(){
  //CHECK WHETHER SENATOR IS HERE
  senator.active->Acquire();
  if(senator.state == waiting){


    printf("\nManager: Senator is waiting, everyone get ready to serve senator!\n");
    senator.state = acknowledged;
    senator.active->Release();

    //Signal all clerk desk 0 to be available to the senator
    int i = 0;

    //Check whether application clerk is on break
    appClerkDesk[i].waitingLine_L->Acquire();
    if(appClerkDesk[i].state == OnBreak){
      printf("\nManager: App Clerk  0 is on break and senator waiting, waking clerk up\n");
      appClerkDesk[i].wakeUp->Signal(appClerkDesk[i].goingOnBreak);
      appClerkDesk[i].waitingLine_L->Release();
    }
    else appClerkDesk[i].waitingLine_L->Release();
    
    //Check whether picture clerk is on break
    picClerkDesk[i].waitingLine_L->Acquire();
    if(picClerkDesk[i].state == OnBreak){
      printf("Manager: Pic Clerk 0 is on break and senator waiting, waking clerk up\n");
      picClerkDesk[i].wakeUp->Signal(picClerkDesk[i].goingOnBreak);
      picClerkDesk[i].waitingLine_L->Release();
    }
    else picClerkDesk[i].waitingLine_L->Release();
    
    //Check  whether the passport clerk is on break
    passClerkDesk[i].waitingLine_L->Acquire();
    if(passClerkDesk[i].state == OnBreak){
      printf("Manager: Pass Clerk 0 is on break and senator waiting, waking clerk up\n");
      passClerkDesk[i].wakeUp->Signal(passClerkDesk[i].goingOnBreak);
      passClerkDesk[i].waitingLine_L->Release();
    }
    else passClerkDesk[i].waitingLine_L->Release();
    
    //Check whether the passport clerk is on break
    cashierDesk[i].waitingLine_L->Acquire();
    if(cashierDesk[i].state == OnBreak){
      printf("Manager: Cashier Clerk 0 is on break and senator waiting, waking clerk up\n");
      cashierDesk[i].wakeUp->Signal(cashierDesk[i].goingOnBreak);
      cashierDesk[i].waitingLine_L->Release();
    }
    else cashierDesk[i].waitingLine_L->Release();
    
  }

  //Senator is finished, restore lines and resume normal operations
  else if(senator.state == finished){
    printf("\nManager: Senator is gone, restoring lines and resuming normal operations");

    //    senator.active->Acquire();
    senator.state = NA;
    senator.active->Release();
   

    //Broadcast code to wake up customers (well, same as c.v. broadcast)
    addCustomerLock->Acquire();
    while(wait_OutsideLine.size()>0){
      wait_OutsideLine.removeCustomer();
      managerRemoveCustomer->Wait(addCustomerLock);
    }
    addCustomerLock->Release();

    while(wait_DecideLine.size() > 0){
      wait_DecideLine.removeCustomer();
    }
    


    for(int i = 0; i<nextAppClerkIndex; i++){
      appClerkDesk[i].waiting_App->Signal(appClerkDesk[i].waitingLine_L);
    }
    for(int i = 0; i<nextPicClerkIndex; i++){
      picClerkDesk[i].waiting_Pic->Signal(picClerkDesk[i].waitingLine_L);
    }
    for(int i = 0; i<nextPassClerkIndex; i++){
      passClerkDesk[i].waiting_App->Signal(passClerkDesk[i].waitingLine_L);
    }
    for(int i = 0; i<nextCashierClerkIndex; i++){
      cashierDesk[i].waiting_App->Signal(cashierDesk[i].waitingLine_L);
    }

    printf("\nManager: Normal Operations Resumed\n");
  }

  //Senator not here, continue normally
  else if(senator.state == NA){
    senator.active->Release();

    bool existClerk = false;

    //Calculate Application Clerk Line size
    printf("\nManager: Checking App Clerks.. total line size is %d", appClerkLine.size()+preferred_appClerkLine.size());
    ////////////////////////////
 
    for(int i=0; i<nextAppClerkIndex; i++){
      appClerkDesk[i].waitingLine_L->Acquire();
      if(appClerkDesk[i].state != OnBreak){
	existClerk = true;
      }
      appClerkDesk[i].waitingLine_L->Release();
    }
  
    if(((appClerkLine.size() + preferred_appClerkLine.size()) >= 3)||((existClerk == false)&&((appClerkLine.size() + preferred_appClerkLine.size()) > 0))){
      for(int i = 0; i <  nextAppClerkIndex; i++){

	appClerkDesk[i].waitingLine_L->Acquire();

	//Check whether application clerk is on break
	if(appClerkDesk[i].state == OnBreak){
	  printf("\nManager: App Clerk is on break and 3+ people waiting or all the clerks are on break and there is someone in the line, waking clerk up");
	  appClerkDesk[i].wakeUp->Signal(appClerkDesk[i].goingOnBreak);
	  appClerkDesk[i].waitingLine_L->Release();
	  break;
	}
	else appClerkDesk[i].waitingLine_L->Release();

      }
    }

    //Calculate picture clerk line size
    printf("\nManager: Checking Pic Clerks.. total line size is %d", picClerkLine.size() + preferred_picClerkLine.size());
    
    existClerk = false;
    for(int i=0; i<nextPicClerkIndex; i++){
      picClerkDesk[i].waitingLine_L->Acquire();
      if(picClerkDesk[i].state != OnBreak){
	existClerk = true;
      }
      picClerkDesk[i].waitingLine_L->Release();
    }

    if(((picClerkLine.size() + preferred_picClerkLine.size()) >= 3)||((existClerk == false)&&((picClerkLine.size() + preferred_picClerkLine.size()) > 0))){
      for(int i = 0; i <  nextPicClerkIndex; i++){

	picClerkDesk[i].waitingLine_L->Acquire();   

     

	//Check whether picture clerk is on break
	if(picClerkDesk[i].state == OnBreak){
	  printf("\nManager: Pic Clerk is on break and 3+ people waiting or all the clerks are on break and there is someone in the line, waking clerk up");
	  picClerkDesk[i].wakeUp->Signal(picClerkDesk[i].goingOnBreak);
	  picClerkDesk[i].waitingLine_L->Release();
	  break;
	}
	else picClerkDesk[i].waitingLine_L->Release();

      }
    }

    printf("\nManager: Checking Pass Clerks.. total line size is %d", passClerkLine.size() + preferred_passClerkLine.size());



    existClerk = false;
    for(int i=0; i<nextPassClerkIndex; i++){
      passClerkDesk[i].waitingLine_L->Acquire();
      if(passClerkDesk[i].state != OnBreak){
	existClerk = true;
      }
      passClerkDesk[i].waitingLine_L->Release();
    }
    if(((passClerkLine.size() + preferred_passClerkLine.size()) >= 3)||((existClerk == false)&&((passClerkLine.size() + preferred_passClerkLine.size()) > 0))){
      for(int i = 0; i <  nextPassClerkIndex; i++){
      
	passClerkDesk[i].waitingLine_L->Acquire();

	//Check  whether the passport clerk is on break
	if(passClerkDesk[i].state == OnBreak){
	  printf("\nManager: Pass Clerk is on break and 3+ people waiting or all the clerks are on break and there is someone in the line, waking clerk up");
	  passClerkDesk[i].wakeUp->Signal(passClerkDesk[i].goingOnBreak);
	  passClerkDesk[i].waitingLine_L->Release();
	  break;
	}
	else passClerkDesk[i].waitingLine_L->Release();

      }
    }

    printf("\nManager: Checking Cashiers.. line size is %d", cashierLine.size() + preferred_cashierLine.size());

    existClerk = false;
    for(int i=0; i<nextCashierClerkIndex; i++){
      cashierDesk[i].waitingLine_L->Acquire();
      if(cashierDesk[i].state != OnBreak){
	existClerk = true;
      }
      cashierDesk[i].waitingLine_L->Release();
    }

    if(((cashierLine.size() + preferred_cashierLine.size()) >= 3)||((existClerk == false)&&((cashierLine.size() + preferred_cashierLine.size()) > 0))){
      for(int i = 0; i <  nextCashierClerkIndex; i++){

	cashierDesk[i].waitingLine_L->Acquire();


	//Check whether the passport clerk is on break
	if(cashierDesk[i].state == OnBreak){
	  printf("\nManager: Cashier Clerk is on break and 3+ people waiting or all the clerks are on break and there is someone in the line, waking clerk up");
	  cashierDesk[i].wakeUp->Signal(cashierDesk[i].goingOnBreak);
	  cashierDesk[i].waitingLine_L->Release();
	  break;
	}
	else cashierDesk[i].waitingLine_L->Release();
     
      }
    }
  }
  //Senator is being served
  else {
    senator.active->Release();
    printf("\nManager: Senator is currently being served");
  }


  //CALCULATE TOTALS AND CHECK LINE SIZE of each clerk
  
  //Clerk array indexes
  //Index 0 -> Application Clerk
  //Index 1 -> Picture Clerk
  //Index 2 -> Passport Clerk
  //Index 3 -> Cashier
  int ClerkTotal[4] = {0};
  
  if(test2doit == true){
    ClerkTotal[0] += appClerkDesk[0].money;
    test2money = ClerkTotal[0];
  }

  if (test6doit == true){
    ClerkTotal[0] +=appClerkDesk[0].money;
    test6money = ClerkTotal[0];
  }


  for(int i = 0; i <  nextAppClerkIndex; i++){
    appClerkDesk[i].waitingLine_L->Acquire();
    //Total up the money
    ClerkTotal[0] += appClerkDesk[i].money;
    appClerkDesk[i].waitingLine_L->Release();
  }
  
  for(int i = 0; i <  nextPicClerkIndex; i++){
    picClerkDesk[i].waitingLine_L->Acquire();   
    //Total up the money
    ClerkTotal[1] += picClerkDesk[i].money;
    picClerkDesk[i].waitingLine_L->Release();
  }
  
  for(int i = 0; i <  nextPassClerkIndex; i++){
    passClerkDesk[i].waitingLine_L->Acquire();
    //Total up the money
    ClerkTotal[2] += passClerkDesk[i].money;
    passClerkDesk[i].waitingLine_L->Release();
  }
  
  for(int i = 0; i <  nextCashierClerkIndex; i++){
    cashierDesk[i].waitingLine_L->Acquire();
    //Total up the money
    ClerkTotal[3] += cashierDesk[i].money;
    cashierDesk[i].waitingLine_L->Release();  
  }
  
  //Print all the totals
  printf("\nManager: Total Money - $%d ", ClerkTotal[0]+ClerkTotal[1]+ClerkTotal[2]+ClerkTotal[3]);
  printf("\n\tApplication Clerk - $%d ", ClerkTotal[0]);
  printf("\n\tPicture Clerk - $%d ", ClerkTotal[1]);
  printf("\n\tPassport Clerk - $%d ", ClerkTotal[2]);
  printf("\n\tCashier - $%d \n", ClerkTotal[3]); 
  
  test2access = false;//reset 

  Finished();
}


//Timer function that will create a new thread for the manager occasionally
void callManager(){
  //DELAY CODE
  manager_runtime++;
  if(manager_runtime % manager_freq != 0){
    return;
  }
  
  //Run the manager thread
  Thread *t = new Thread("Manager");
  t->Fork((VoidFunctionPtr)ManagerMainLoop,0);
}


/*
  ----------------------------------
  *
  * TEST FUNCTIONS:
  *
  * test 1: Customers always take the shortest line, but no 2 customers
  ever choose the same shortest line at the same time
  ----------------------------------
*/
Lock * testLock = new Lock("test lock");


void test1()
{
  /*
    Test 1: Customers always take the shortest line, but no 2 customers ever choose the same shortest line at the same time.
    1. make two customers.
    2. let the two customers add themselves to line. (in customer code, there is a way to compare picClerkLine size and appClerkLine size.  If the length is same, first customer will go to appClerk.  If appClerk's line size is longer than picClerk's line size, customer will go to picture clerk.
    3. since there are two customers, test is successful if there is one customer in each line.  If two customers lines up in the same line, the test will fail.
  */
  testLock->Acquire();
  Thread *t;
  t = new Thread("Customer");
  t->Fork((VoidFunctionPtr)CustomerMainLoop,0);
  
  t = new Thread("Customer");
  t->Fork((VoidFunctionPtr)CustomerMainLoop,0);  
  printf("Test 1 Start\n");
  //check if both are in separate lines
  while(true)
    {
      if(appClerkLine.size() == 1 &&
	 picClerkLine.size() == 1)
	{
	  printf("Test 1: passed, 1 customer in each line\n");
	  break;
	  
	}
      else if(appClerkLine.size() > 1 ||
	      picClerkLine.size() > 1)
	{
	  printf("Test 1: failed!\n");
	  break;
	  
	}
      currentThread->Yield();
    }
  printf("Test 1 Terminated\n");
  
  nextSSN = 0;
  testLock->Release();
  
  return;
}

void test2()
{
  /*
    Test 2: Managers only read from one Clerk's total money at a time
    1. alternate between giving clerks money and displaying the total 
    money 
    2. check that the manager gets the money when the money is available to read
  */
  

  appClerkDesk[0].waitingLine_L = new Lock("waiting line_L");
 

   nextAppClerkIndex ++;
   totalCust++;
   test6doit = true;
  bool testPassed = true;
   test2doit = true;
     manager_freq = 1;

      appClerkDesk[0].money += 10;
       printf("Application Clerk 0 money is: %d\n", appClerkDesk[0].money);
        test2access = true;
	while(test6money == 0)
	 {
	     ManagerMainLoop();

	 }

     

     
      appClerkDesk[0].money += 10;
      printf("Application Clerk 0 money is: %d\n", appClerkDesk[0].money);
      printf("Runing manager code without releasing application clerk 0 money lock\n");
      
 
	  printf("Test Passed\n");

  
}
void test3()
{
  /*
    Test 3: Customers do not leave until they are given thier passport by the Cashier.
    The Cashier does not start on another customer until they know the last Customer has left
    their area.
    1. let regular customer get in cashier line
    2. send in mock customer first and do interaction
    3. before mock custmer is done let real customer be serviceable
  */

  Thread *t;
  
  //Timer *manager = new Timer((VoidFunctionPtr)callManager, 0, false);
  t = new Thread("Customer");
  t->Fork((VoidFunctionPtr)CustomerMainLoop,0);
  totalCust++;
   
  
  t = new Thread("AppClerk0");
  t->Fork((VoidFunctionPtr)ApplicationClerk,0);
 
  t = new Thread("PicClerk0");
  t->Fork((VoidFunctionPtr)PictureClerk,0);
  
  t = new Thread("PassClerk0");
  t->Fork((VoidFunctionPtr)PassportClerk,0);

  
   
    while(true)
     {
       if(cashierLine.size() == 1)
	 {
	   break;
	 }

        if(appClerkDesk[0].state == OnBreak ||
	  picClerkDesk[0].state == OnBreak ||
	  passClerkDesk[0].state == OnBreak ||
	  cashierDesk[0].state == OnBreak)
	 {
	   ManagerMainLoop();
	 
	 }
       
        currentThread->Yield();
     }
        
    printf("\nSTOPPING CUSTOMER AND SENDING IN MOCK CUSTOMER OF SSN 100\n");
    cashierDesk[0].SSN = 100;
    cashierLine.setSize(0);
    preferred_cashierLine.setSize(1);
    
   t = new Thread("Cashier0");
   t->Fork((VoidFunctionPtr)CashierClerk,0);

   while(true)
     {
       if(cashierDesk[0].state == WaitingOnCustomer)
	 {
	   printf("\nCASHIER WAITING ON MOCK CUSTOMER\n");
	   break;
	 }
       
         currentThread->Yield();
     }
   
   cashierLine.setSize(1);
   printf("\nMOCK CUSTOMER NOT LEFT AREA, BUT ALLOWING REAL CUSTOMER TO BE SERVED\n");
  

   currentThread->Yield();
   
   
   printf("\nMOCK CUSTOMER FINISHED!\nNOW DEMONSTRATION OF SECOND PART OF TEST\n");
   cashierDesk[0].passState = empty;
   cashierDesk[0].waiting_App->Signal(cashierDesk[0].waitingLine_L);

   currentThread->Yield();

   bool testDone = false;
   while(!testDone)
     {
       if(totalCust == 0)
	 {
	   printf("\nTEST PASSED\n");
	   ManagerMainLoop();
	   testDone = true;
	 }
       if(totalCust == 0 &&
	  passDone[0] == LARGENUMBER)
	 {
	   printf("\nTEST FAILED\n");
	   testDone = true;
	 }
       currentThread->Yield();
     }


}
void test4(){
  /*
    Test4: Clerk go on break when they have no one waiting in their line.
    1. add all four types of clerks (one of each).
    2. yield to allow all threads to have sometime.
    3. the test is successful if everyone goes on a break.  If not, it fails.
  */
  testLock->Acquire();
  Thread *t;
  
  t = new Thread("Application Clerk");
  t->Fork((VoidFunctionPtr)ApplicationClerk,0);
  t = new Thread("Picture Clerk");
  t->Fork((VoidFunctionPtr)PictureClerk,0);
  t = new Thread("Passport Clerk");
  t->Fork((VoidFunctionPtr)PassportClerk,0);
  t = new Thread("Cashier");
  t->Fork((VoidFunctionPtr)CashierClerk,0);
 
  while(appClerkDesk[0].state != OnBreak || picClerkDesk[0].state != OnBreak || passClerkDesk[0].state != OnBreak || cashierDesk[0].state != OnBreak){
    currentThread->Yield();
  }
   
  if(appClerkDesk[0].state == OnBreak && picClerkDesk[0].state == OnBreak && passClerkDesk[0].state == OnBreak && cashierDesk[0].state == OnBreak){
    printf("Test4: passed, When there is no customer all the clerks will go on break\n"); 
  }
  else{
    printf("Test4 : failed\n");
  }
   
  testLock->Release();
  //testDone.P();
  return;
}
void test5(){
  /*
    Test5: Managers get Clerks off their break when lines get too long.
    1. add all four types of clerks (one of each).
    2. yield to give some time for each clerks.
    3. since there is no customer, everyone should go on a break
    4. manually change the length of each clerklines.
    5. the test is successful if everyone comes back from break.  If there is any clerk who doesnt come back to from break, test fails.
  */

  testLock->Acquire();
  Thread *t;

  t = new Thread("Application Clerk");
  t->Fork((VoidFunctionPtr)ApplicationClerk,0);
  t = new Thread("Picture Clerk");
  t->Fork((VoidFunctionPtr)PictureClerk,0);
  t = new Thread("Passport Clerk");
  t->Fork((VoidFunctionPtr)PassportClerk,0);
  t = new Thread("Cashier");
  t->Fork((VoidFunctionPtr)CashierClerk,0);
 
  while(appClerkDesk[0].state != OnBreak || picClerkDesk[0].state != OnBreak || passClerkDesk[0].state != OnBreak || cashierDesk[0].state != OnBreak){
    currentThread->Yield();
  }
  
  appClerkLine.setSize(2);
  preferred_appClerkLine.setSize(1);
  picClerkLine.setSize(3);
  preferred_picClerkLine.setSize(0);
  passClerkLine.setSize(4);
  preferred_passClerkLine.setSize(2);
  cashierLine.setSize(3);
  preferred_cashierLine.setSize(3);
  
  ManagerMainLoop();
  
  while(appClerkDesk[0].state == OnBreak || picClerkDesk[0].state == OnBreak || passClerkDesk[0].state == OnBreak || cashierDesk[0].state == OnBreak){
    currentThread->Yield();
  }

  if(appClerkDesk[0].state != OnBreak && picClerkDesk[0].state != OnBreak && passClerkDesk[0].state != OnBreak && cashierDesk[0].state != OnBreak){
    printf("Test5: passed,  Manager gets all clerks to come back from break when there are more than 3 customers in line\n"); 
  }
  else{
    printf("Test5 : failed\n");
  }
  testLock->Release();
  
  return;

  
}
void test6(){
  /*
    Test6: Total sales never suffers from a race condition.
    1. manually change the amount of money carried by appClerkDesk zero.  
    2. run the managerMainLoop function to record the money
    3. check if the current money held by appClerkDesk zero and the money recorded by the manager is same.
    4. if its the same, print out "this recording did not suffer race condition."
    5. repeat 1-4 for 10 times and see if any of the recordings suffer from race condition.
    6. test is successful if all recordings did not suffer race condition.  if there is any recording that is not successful, test fails.
  */
  testLock->Acquire();
  Thread *t;
  manager_freq = 1;

  totalCust = 1;
  test6doit = true;
  bool raceCondition = false;



  for(int i=0;i<10;i++){
    appClerkDesk[0].money += 100*i;
    printf("new Money: %d\n",appClerkDesk[0].money);
    ManagerMainLoop();
    if(appClerkDesk[0].money == test6money){
      printf("This recording did not suffer race conditions\n");
    }
    else{
      raceCondition = true;
    }
    if(i==9){
      totalCust=0;
    }
  }
  if(raceCondition == false){
    printf("Test6 : passed.  All of the recordings did not suffer race conditions.\n");
  }
  else{
    printf("Test6 : failed.");
  }
  totalCust = 0;
  //ManagerMainLoop();
  testLock->Release();
  //testDone.P();
  return;
}
void test7(){
  /*
    Test7: The behavior of Customer is proper when Senator arrive.  This is before during and after.
    1. add manager, each clerk types, and six customers.
    2. 
  */
  testLock->Acquire();
  //INITIALIZE SOME VALUES

  Thread *t;
  
  //Create the clerks and manager
  Timer *manager = new Timer((VoidFunctionPtr)callManager, 0, false);
  
  t = new Thread("AppClerk0");
  t->Fork((VoidFunctionPtr)ApplicationClerk,0);
  
  t = new Thread("PicClerk0");
  t->Fork((VoidFunctionPtr)PictureClerk,0);
  
  t = new Thread("PassClerk0");
  t->Fork((VoidFunctionPtr)PassportClerk,0);
  
  t = new Thread("Cashier0");
  t->Fork((VoidFunctionPtr)CashierClerk,0);
  
  senatorIsHere();
  //Create the customers
  for(int i=0;i<6;i++){
    t = new Thread("Customer");
    t->Fork((VoidFunctionPtr)CustomerMainLoop,0);
    totalCust++;
  }   
  
  testLock->Release();
  //testDone.P();
  return;
  
}

/*
  ----------------------------------
  *
  * PROBLEM 2 - MAIN SIMULATION LOOP
  *
  ----------------------------------
*/



void Problem2()
{

  //INITIALIZE SOME VALUES
  senator.state = NA;
  senator.active = new Lock("Senator active_L");
  senator.waiting = new Condition("Senator waiting_CV");

  for(int i=0; i<MAXCUSTOMERS; i++){
    appOK[i] = LARGENUMBER;
    picOK[i] = LARGENUMBER;
    passOK[i] = LARGENUMBER;
    passDone[i] = LARGENUMBER;
  }



  Thread *t;

  //Create the clerks and manager
  //   Timer *manager = new Timer((VoidFunctionPtr)callManager, 0, false);
  //  printf("start\n");

  int menu;
  bool runtest = true;

  printf("\n\nMENU\n\n");
  printf("Test1: Customers always take the shortest line, but no 2 customers ever choose the same shortest line at the same time.\n");
  printf("Test2: Managers only read one from one Clerk's total money received, at a time.\n");
  printf("Test3: Customers do not leave until they are given their passport by the Cashier. The Cashier does not start on another customer until they know that the last Customer has left their area.\n");
  printf("Test4: Clerks go on break when they have no one waiting in their line.\n");
  printf("Test5: Managers get Clerks off their break when lines get too long.\n");
  printf("Test6: Total sales never suffers from a race condition.\n");
  printf("Test7: The behavior of Customers is proper when Senators arrive. This is before, during, and after.\n");
  printf("\nPlease type the test number (ex. to run test3, type '3') to run the test.\n");
 
 
  while(runtest){
    scanf("%d",&menu);
    runtest = false;
    switch(menu)
      {
      case 1:
	t = new Thread("test1");
	t->Fork((VoidFunctionPtr)test1,0);
	break;
      case 2:
	t = new Thread("test2");
	t->Fork((VoidFunctionPtr)test2,0);
	break;
      case 3:
	t = new Thread("test3");
	t->Fork((VoidFunctionPtr)test3,0);
	break;
      case 4:
	t = new Thread("test4");
	t->Fork((VoidFunctionPtr)test4,0);
	break;
      case 5:
	t = new Thread("test5");
	t->Fork((VoidFunctionPtr)test5,0);
	break;
      case 6:
	t = new Thread("test6");
	t->Fork((VoidFunctionPtr)test6,0);
	break;
      case 7:
	t = new Thread("test7");
	t->Fork((VoidFunctionPtr)test7,0);
	break;
      default: 
	printf("Error: Please select from number 1 to 7.\n");
	runtest = true;
	break;
      }
  }



   


  

  
}
#endif

#endif
